home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 2001 May / SGI Freeware 2001 May - Disc 1.iso / dist / fw_mysql.idb / usr / freeware / share / sql-bench / crash-me.z / crash-me
Encoding:
Text File  |  1999-10-18  |  81.4 KB  |  2,888 lines

  1. #!/usr/bin/perl
  2. # Copyright (C) 1997 TcX AB & Monty Program KB & Detron HB
  3. #
  4. # This programs tries to find all limits for a sql server
  5. # It gets the name from what it does to most servers :)
  6. #
  7. # This software is distributed with NO WARRANTY OF ANY KIND.  No author or
  8. # distributor accepts any responsibility for the consequences of using it, or
  9. # for whether it serves any particular purpose or works at all, unless he or
  10. # she says so in writing.  Refer to the Free Public License (the "License")
  11. # for full details.
  12. #
  13. # Be sure to use --help before running this!
  14. #
  15. # Written by Monty for the TCX/Monty Program/Detron benchmark suite.
  16. # empress patches by Luuk de Boer
  17. #
  18. # If you want to add support for another server, add a new package for the
  19. # server in server-cfg.  You only have to support the 'new' and 'version'
  20. # functions. new doesn't need to have any limits if one doesn't want to
  21. # use the benchmarks.
  22. #
  23.  
  24. $version="1.24";
  25.  
  26. use DBI;
  27. use Getopt::Long;
  28. chomp($pwd = `pwd`); $pwd = "." if ($pwd eq '');
  29. require "$pwd/server-cfg" || die "Can't read Configuration file: $!\n";
  30.  
  31. $opt_server="mysql"; $opt_host="localhost"; $opt_database="test";
  32. $opt_dir="limits";
  33. $opt_debug=$opt_help=$opt_Information=$opt_restart=$opt_force=$opt_quick=0;
  34. $opt_log_all_queries=$opt_fix_limit_file=$opt_batch_mode=0;
  35. $opt_db_start_cmd="";           # the db server start command
  36. $opt_sleep=10;                  # time to sleep while starting the db server
  37. $limit_changed=0;               # For configure file
  38. $reconnect_count=0;
  39. $opt_comment="";
  40. $limits{'crash_me_safe'}='yes';
  41. $prompts{'crash_me_safe'}='crash me safe';
  42. $limits{'operating_system'}= machine();
  43. $prompts{'operating_system'}='crash-me tested on';
  44. $retry_limit=3;
  45.  
  46. GetOptions("Information","help","server=s","debug","user=s","password=s","database=s","restart","force","quick","log-all-queries","comment=s","host=s","fix-limit-file","dir=s","db-start-cmd=s","sleep=s","batch-mode") || usage();
  47. usage() if ($opt_help || $opt_Information);
  48.  
  49. if ($opt_fix_limit_file)
  50. {
  51.   print "Fixing limit file for $opt_server\n";
  52.   read_config_data();
  53.   $limit_changed=1;
  54.   save_all_config_data();
  55.   exit 0;
  56. }
  57.  
  58. $server=get_server($opt_server,$opt_host,$opt_database);
  59. $opt_server=$server->{'cmp_name'};
  60.  
  61. $|=1;                           # For debugging
  62.  
  63. print "Running $0 $version on '",($server_version=$server->version()),"'\n\n";
  64. print "I hope you didn't have anything important running on this server....\n";
  65. read_config_data();
  66. if ($limit_changed)             # Must have been restarted
  67. {
  68.   save_config_data('crash_me_safe','no',"crash me safe");
  69. }
  70.  
  71. if (!$opt_force && !$opt_batch_mode)
  72. {
  73.   server_info();
  74. }
  75. else
  76. {
  77.   print "Using --force.  I assume you know what you are doing...\n";
  78. }
  79. print "\n";
  80.  
  81. save_config_data('crash_me_version',$version,"crash me version");
  82. if ($server_version)
  83. {
  84.   save_config_data('server_version',$server_version,"server version");
  85. }
  86. if (length($opt_comment))
  87. {
  88.   save_config_data('user_comment',$opt_comment,"comment");
  89. }
  90.  
  91.  
  92. #
  93. # Set up some limits that's regared as unlimited
  94. # We don't want to take up all resources from the server...
  95. #
  96.  
  97. $max_connections="+1000";       # Number of simultanious connections
  98. $max_buffer_size="+16000000";   # size of communication buffer.
  99. $max_string_size="+8000000";    # Enough for this test
  100. $max_name_length="+512";        # Actually 256, but ...
  101. $max_keys="+64";                # Probably too big.
  102. $max_join_tables="+64";         # Probably too big.
  103. $max_columns="+8192";           # Probably too big.
  104. $max_row_length=$max_string_size;
  105. $max_key_length="+8192";        # Big enough
  106. $max_order_by="+64";        # Big enough
  107. $query_size=$max_buffer_size;
  108. #
  109. # First do some checks that needed for the rest of the benchmark
  110. #
  111. use sigtrap;               # Must be removed with perl5.005_2 on Win98
  112. $SIG{PIPE} = 'IGNORE';
  113. $SIG{SEGV} = sub {warn('SEGFAULT')};
  114. $dbh=safe_connect();
  115. $dbh->do("drop table crash_me");        # Remove old run
  116. $dbh->do("drop table crash_q");         # Remove old run
  117.  
  118. $prompt="Tables without primary key";
  119. if (!safe_query(["create table crash_me (a integer not null,b char(10) not null)",
  120.          "insert into crash_me (a,b) values (1,'a')"]))
  121. {
  122.   if (!safe_query(["create table crash_me (a integer not null,b char(10) not null, primary key (a))",
  123.            "insert into crash_me (a,b) values (1,'a')"]))
  124.   {
  125.     die "Can't create table 'crash_me' with one record: $DBI::errstr\n";
  126.   }
  127.   save_config_data('no_primary_key',"no",$prompt);
  128. }
  129. else
  130. {
  131.   save_config_data('no_primary_key',"yes",$prompt);
  132. }
  133.  
  134. print "$prompt: $limits{'no_primary_key'}\n";
  135.  
  136. report("SELECT without FROM",'select_without_from',"select 1");
  137. if ($limits{'select_without_from'} ne "yes")
  138. {
  139.   $end_query=" from crash_me";
  140.   $check_connect="select a from crash_me";
  141. }
  142. else
  143. {
  144.   $end_query="";
  145.   $check_connect="select 1";
  146. }
  147.  
  148. assert($check_connect);
  149. assert("select a from crash_me where b<'b'");
  150.  
  151. report("Select constants",'select_constants',"select 1 $end_query");
  152. report("Select table_name.*",'table_wildcard',
  153.        "select crash_me.* from crash_me");
  154. report("Allows \' and \" as string markers",'quote_with_"',
  155.        'select a from crash_me where b<"c"');
  156. check_and_report("Double '' as ' in strings",'double_quotes',[],
  157.          "select 'Walker''s' $end_query",[],"Walker's",1);
  158. check_and_report("Multiple line strings","multi_strings",[],
  159.          "select a from crash_me where b < 'a'\n'b'",[],"1",0);
  160. report("Column alias","column_alias","select a as ab from crash_me");
  161. report("Table alias","table_alias","select b.a from crash_me as b");
  162. report("Functions",'functions',"select 1+1 $end_query");
  163. report("Group functions",'group_functions',"select count(*) from crash_me");
  164. report("Group functions with distinct",'group_distinct_functions',
  165.        "select count(distinct a) from crash_me");
  166. report("Group by",'group_by',"select a from crash_me group by a");
  167. report("Group by position",'group_by_position',
  168.        "select a from crash_me group by 1");
  169. report("Group by alias",'group_by_alias',
  170.        "select a as ab from crash_me group by ab");
  171. report("Order by",'order_by',"select a from crash_me order by a");
  172. report("Order by position",'order_by_position',
  173.        "select a from crash_me order by 1");
  174. report("Compute",'compute',
  175.        "select a from crash_me order by a compute sum(a) by a");
  176. report("Value lists in INSERT",'multi_value_insert',
  177.        "create table crash_q (s char(10))",
  178.        "insert into crash_q values ('a'),('b')",
  179.        "drop table crash_q");
  180. report("INSERT with set syntax",'insert_with_set',
  181.        "create table crash_q (a integer)",
  182.        "insert into crash_q SET a=1",
  183.        "drop table crash_q");
  184. report("allows end ';'","end_colon", "select * from crash_me;");
  185.  
  186. # The following alter table commands MUST be kept together!
  187. $dbh->do("create table crash_q (a integer, b integer,c CHAR(10))")  ||
  188.   die "Can't create test table for alter table";
  189. report("Alter table add column",'alter_add_col',
  190.        "alter table crash_q add d integer");
  191. report_one("Alter table add many columns",'alter_add_multi_col',
  192.        [["alter table crash_q add f integer,add g integer","yes"],
  193.         ["alter table crash_q add f integer,g integer","without add"]] );
  194. report("Alter table change column",'alter_change_col',
  195.        "alter table crash_q change a e char(50)");
  196. # informix can only change data type with modify
  197. report("Alter table modify column",'alter_modify_col',
  198.        "alter table crash_q modify c CHAR(20)");
  199. report("Alter table alter column",'alter_alter_col',
  200.        "alter table crash_q alter b set default NULL");
  201. report("Alter table drop column",'alter_drop_col',
  202.        "alter table crash_q drop b");
  203. report("Alter table rename table",'alter_rename_table',
  204.        "alter table crash_q rename crash_q1");
  205. # Make sure the both tables will be dropped, even if rename fails.
  206. $dbh->do("drop table crash_q1");
  207. $dbh->do("drop table crash_q");
  208.  
  209. check_and_report("case insensitive compare","case_insensitive_strings",
  210.          [],"select b from crash_me where b = 'A'",[],'a',1);
  211. check_and_report("ignore end space in compare","ignore_end_space",
  212.          [],"select b from crash_me where b = 'a '",[],'a',1);
  213. check_and_report("group on column with null values",'group_by_null',
  214.          ["create table crash_q (s char(10))",
  215.           "insert into crash_q values(null)",
  216.           "insert into crash_q values(null)"],
  217.          "select count(*) from crash_q group by s",
  218.          ["drop table crash_q"],2,0);
  219.  
  220. $prompt="Having";
  221. if (!defined($limits{'having'}))
  222. {                               # Complicated because of postgreSQL
  223.   if (!safe_query_result("select a from crash_me group by a having a > 0",1,0))
  224.   {
  225.     if (!safe_query_result("select a from crash_me group by a having a < 0",
  226.                1,0))
  227.     { save_config_data("having","error",$prompt); }
  228.     else
  229.     { save_config_data("having","yes",$prompt); }
  230.   }
  231.   else
  232.   { save_config_data("having","no",$prompt); }
  233. }
  234. print "$prompt: $limits{'having'}\n";
  235.  
  236. if ($limits{'having'} eq 'yes')
  237. {
  238.   report("Having with group function","having_with_group",
  239.      "select a from crash_me group by a having count(*) = 1");
  240. }
  241.  
  242. if ($limits{'column_alias'} eq 'yes')
  243. {
  244.   report("Order by alias",'order_by_alias',
  245.      "select a as ab from crash_me order by ab");
  246.   if ($limits{'having'} eq 'yes')
  247.   {
  248.     report("Having on alias","having_with_alias",
  249.        "select a as ab from crash_me group by a having ab > 0");
  250.   }
  251. }
  252. report("binary items (0x41)","binary_items","select 0x41 $end_query");
  253.  
  254. report_result("Value of logical operation (1=1)","logical_value",
  255.           "select (1=1) $end_query");
  256.  
  257. $logical_value= $limits{'logical_value'};
  258.  
  259. #
  260. # Check how many connections the server can handle:
  261. # We can't test unlimited connections, because this may take down the
  262. # server...
  263. #
  264.  
  265. $prompt="Simultaneous connections";
  266. print "$prompt: ";
  267. if (defined($limits{'connections'}))
  268. {
  269.   print "$limits{'connections'}\n";
  270. }
  271. else
  272. {
  273.   @connect=($dbh);
  274.  
  275.   for ($i=1; $i < $max_connections ; $i++)
  276.   {
  277.     if (!($dbh=DBI->connect($server->{'data_source'},$opt_user,$opt_password,
  278.               { PrintError => 0})))
  279.     {
  280.       print "Last connect error: $DBI::errstr\n" if ($opt_debug);
  281.       last;
  282.     }
  283.     $dbh->{LongReadLen}= 16000000; # Set retrieval buffer
  284.     print "." if ($opt_debug);
  285.     push(@connect,$dbh);
  286.   }
  287.   print "$i\n";
  288.   save_config_data('connections',$i,$prompt);
  289.   foreach $dbh (@connect)
  290.   {
  291.     print "#" if ($opt_debug);
  292.     $dbh->disconnect;           # close connection
  293.   }
  294.  
  295.   $#connect=-1;                 # Free connections
  296.  
  297.   if ($i == 0)
  298.   {
  299.     print "Can't connect to server: $DBI::errstr.  Please start it and try again\n";
  300.     exit 1;
  301.   }
  302.   $dbh=safe_connect();
  303. }
  304.  
  305.  
  306. #
  307. # Check size of communication buffer, strings...
  308. #
  309.  
  310. $prompt="query size";
  311. print "$prompt: ";
  312. if (!defined($limits{'query_size'}))
  313. {
  314.   $query="select ";
  315.   $first=64;
  316.   $end=$max_buffer_size;
  317.   $select= $limits{'select_without_from'} eq 'yes' ? 1 : 'a';
  318.  
  319.   assert($query . "$select$end_query");
  320.  
  321.   $first=$limits{'restart'}{'low'} if ($limits{'restart'}{'low'});
  322.  
  323.   if ($limits{'restart'}{'tohigh'})
  324.   {
  325.     $end = $limits{'restart'}{'tohigh'} - 1;
  326.     print "\nRestarting this with low limit: $first and high limit: $end\n";
  327.     delete $limits{'restart'};
  328.     $first=$first+int(($end-$first+4)/5);           # Prefere lower on errors
  329.   }
  330.   for ($i=$first ; $i < $end ; $i*=2)
  331.   {
  332.     last if (!safe_query($query . (" " x ($i - length($query)-length($end_query) -1)) . "$select$end_query"));
  333.     $first=$i;
  334.     save_config_data("restart",$i,"") if ($opt_restart);
  335.   }
  336.   $end=$i;
  337.  
  338.   if ($i < $max_buffer_size)
  339.   {
  340.     while ($first != $end)
  341.     {
  342.       $i=int(($first+$end+1)/2);
  343.       if (safe_query($query .
  344.              (" " x ($i - length($query)-length($end_query) -1)) .
  345.              "$select$end_query"))
  346.       {
  347.     $first=$i;
  348.       }
  349.       else
  350.       {
  351.     $end=$i-1;
  352.       }
  353.     }
  354.   }
  355.   save_config_data('query_size',$end,$prompt);
  356. }
  357. $query_size=$limits{'query_size'};
  358.  
  359. print "$limits{'query_size'}\n";
  360. #
  361. # Test database types
  362. #
  363.  
  364. @sql_types=("character(1)","char(1)","char varying(1)", "character varying(1)",
  365.         "varchar(1)",
  366.         "integer","int","numeric(9,2)","decimal(6,2)","dec(6,2)",
  367.         "bit", "bit(2)","bit varying(2)","float","float(6,2)","real",
  368.         "double","double precision", "date","time","timestamp",
  369.         "interval year");
  370. @odbc_types=("binary(1)","varbinary(1)","tinyint","smallint","bigint",
  371.          "datetime");
  372. @extra_types=("blob","byte","long varbinary","image","text","text(10)",
  373.           "mediumtext",
  374.           "char2","char4","char8","char16","nvarchar(6,2)","nchar(1)",
  375.           "long varchar(1)",
  376.           "mediumint","middleint","int unsigned",
  377.           "int1","int2","int3","int4","int8","uint",
  378.           "money","smallmoney","float4","float8","smallfloat",
  379.           "enum('red')","set('red')", "int(5) zerofill", "serial",
  380.           "char(10) binary","int not null auto_increment,unique(q)",
  381.           "abstime","year","datetime","smalldatetime","timespan","reltime",
  382.           "box","bool","circle","polygon","point","line","lseg","path", # postgres types
  383.           "varchar2(16)","nvarchar2(16)","number(9,2)","number(9)","number","float(6)", # oracle types
  384.         "long","raw(16)","long raw","rowid","mlslabel","clob","nclob","bfile" # oracle types
  385.           );
  386.  
  387. @types=(["sql",\@sql_types],
  388.     ["odbc",\@odbc_types],
  389.     ["extra",\@extra_types]);
  390.  
  391. foreach $types (@types)
  392. {
  393.   print "\nSupported $types->[0] types\n";
  394.   $tmp=@$types->[1];
  395.   foreach $use_type (@$tmp)
  396.   {
  397.     $type=$use_type;
  398.     $type =~ s/\(.*\)/(1 arg)/;
  399.     if (index($use_type,",")>= 0)
  400.     {
  401.       $type =~ s/\(1 arg\)/(2 arg)/;
  402.     }
  403.     if (($tmp2=index($type,",unique")) >= 0)
  404.     {
  405.       $type=substr($type,0,$tmp2);
  406.     }
  407.     $tmp2=$type;
  408.     $tmp2 =~ s/ /_/g;
  409.     $tmp2 =~ s/_not_null//g;
  410.     report("Type $type","type_$types->[0]_$tmp2",
  411.        "create table crash_q (q $use_type)",
  412.        "drop table crash_q");
  413.   }
  414. }
  415.  
  416. #
  417. # Test some type limits
  418. #
  419.  
  420. check_and_report("Remembers end space in char()","remember_end_space",
  421.          ["create table crash_q (a char(10))",
  422.           "insert into crash_q values('hello ')"],
  423.          "select a from crash_q where a = 'hello '",
  424.          ["drop table crash_q"],
  425.          'hello ',6);
  426.  
  427. check_and_report("Remembers end space in varchar()",
  428.          "remember_end_space_varchar",
  429.          ["create table crash_q (a varchar(10))",
  430.           "insert into crash_q values('hello ')"],
  431.          "select a from crash_q where a = 'hello '",
  432.          ["drop table crash_q"],
  433.          'hello ',6);
  434.  
  435. check_and_report("Supports 0000-00-00 dates","date_zero",
  436.          ["create table crash_me2 (a date not null)",
  437.           "insert into crash_me2 values ('0000-00-00')"],
  438.          "select a from crash_me2",
  439.          ["drop table crash_me2"],
  440.          "0000-00-00",1);
  441.  
  442. if (!defined($limits{'date_with_YY'}))
  443. {
  444.     check_and_report("Supports YY-MM-DD dates","date_with_YY",
  445.              ["create table crash_me2 (a date not null)",
  446.               "insert into crash_me2 values ('98-03-03')"],
  447.              "select a from crash_me2",
  448.              ["drop table crash_me2"],
  449.              "1998-03-03",5);
  450.     if ($limits{'date_with_YY'} eq "yes")
  451.     {
  452.     undef($limits{'date_with_YY'});
  453.     check_and_report("Supports YY-MM-DD 2000 compilant dates",
  454.              "date_with_YY",
  455.              ["create table crash_me2 (a date not null)",
  456.               "insert into crash_me2 values ('10-03-03')"],
  457.              "select a from crash_me2",
  458.              ["drop table crash_me2"],
  459.              "2010-03-03",5);
  460.     }
  461. }
  462.  
  463. if ($limits{'type_sql_float(2_arg)'} eq "yes" ||
  464.     $limits{'type_sql_decimal(2_arg)'} eq "yes")
  465. {
  466.   my $type=$limits{'type_sql_float(2_arg)'} eq "yes" ? "float(4,1)" :
  467.     "decimal(4,1)";
  468.   if (check_and_report("Correct rounding when storing float values",
  469.                "round_on_store",
  470.                ["create table crash_q (q1 $type)",
  471.             "insert into crash_q values(1.14)"],
  472.                "select q1 from crash_q",
  473.                ["drop table crash_q"],1.10,0,
  474.                undef(),1))
  475.   {
  476.     check_and_report("Correct rounding when storing float values",
  477.              "round_on_store",
  478.              ["create table crash_q1 (q1 $type)",
  479.               "insert into crash_q1 values(1.16)"],
  480.              "select q1 from crash_q1",
  481.              ["drop table crash_q1"],1.20,0,
  482.              1);
  483.   }
  484. }
  485. #
  486. # Test functions
  487. #
  488.  
  489. @sql_functions=
  490.   (["+, -, * and /","+","5*3-4/2+1",14,0],
  491.    ["concatenation with ||","concat_as_||","'abc' || 'def'","abcdef",1],
  492.    ["BIT_LENGTH","bit_length","bit_length('abc')",24,0],
  493.    ["CHAR_LENGTH","char_length","char_length('abcd')","4",0],
  494.    ["CAST","cast","CAST(1 as CHAR)","1",1],
  495.    ["CASE","case","case when 1 > 2 then 'false' when 2 > 1 then 'true' end",
  496.     "true",1],
  497.    ["CHARACTER_LENGTH","character_length","character_length('abcd')","4",0],
  498.    ["CURRENT_DATE()","current_date()","current_date()",0,2],
  499.    ["CURRENT_DATE","current_date","current_date",0,2],
  500.    ["CURRENT_TIME()","current_time()","current_time()",0,2],
  501.    ["CURRENT_TIME","current_time","current_time",0,2],
  502.    ["CURRENT_TIMESTAMP()","current_timestamp()","current_timestamp()",0,2],
  503.    ["CURRENT_TIMESTAMP","current_timestamp","current_timestamp",0,2],
  504.    ["LOWER","lower","LOWER('ABC')","abc",1],
  505.    ["OCTET_LENGTH","octet_length","octet_length('abc')",3,0],
  506.    ["POSITION","position","position('ll' in 'hello')",3,0],
  507.    ["SESSION_USER","session_user","session_user()",0,2],
  508.    ["ANSI SQL SUBSTRING","substring","substring('abcd' from 2 for 2)","bc",1],
  509.    ["SYSDATE","sysdate","sysdate()",0,2],
  510.    ["SYSTEM_USER","system_user","system_user()",0,2],
  511.    ["TRIM","trim","trim(trailing from trim(LEADING FROM ' abc '))","abc",1],
  512.    ["UPPER","upper","UPPER('abc')","ABC",1],
  513.    );
  514.  
  515. @odbc_functions=
  516.   (["ASCII", "ascii", "ASCII('A')","65",0],
  517.    ["CHAR", "char", "CHAR(65)"  ,"A",1],
  518.    ["CONCAT(2 arg)","concat", "concat('a','b')","ab",1],
  519.    ["DIFFERENCE()","difference","difference('abc','abe')",0,2],
  520.    ["INSERT","insert","insert('abcd',2,2,'ef')","aefd",1],
  521.    ["LEFT","left","left('abcd',2)","ab",1],
  522.    ["LTRIM","ltrim","ltrim('   abcd')","abcd",1],
  523.    ["REAL LENGTH","length","length('abcd ')","5",0],
  524.    ["ODBC LENGTH","length_without_space","length('abcd ')","4",0],
  525.    ["LOCATE(2 arg)","locate_2","locate('bcd','abcd')","2",0],
  526.    ["LOCATE(3 arg)","locate_3","locate('bcd','abcd',3)","0",0],
  527.    ["LCASE","lcase","lcase('ABC')","abc",1],
  528.    ["REPEAT","repeat","repeat('ab',3)","ababab",1],
  529.    ["REPLACE","replace","replace('abbaab','ab','ba')","bababa",1],
  530.    ["RIGHT","right","right('abcd',2)","cd",1],
  531.    ["RTRIM","rtrim","rtrim(' abcd  ')"," abcd",1],
  532.    ["SPACE","space","space(5)","     ",3],
  533.    ["SOUNDEX","soundex","soundex('hello')",0,2],
  534.    ["ODBC SUBSTRING","substring","substring('abcd',3,2)","cd",1],
  535.    ["UCASE","ucase","ucase('abc')","ABC",1],
  536.  
  537.    ["ABS","abs","abs(-5)",5,0],
  538.    ["ACOS","acos","acos(0)","1.570796",0],
  539.    ["ASIN","asin","asin(1)","1.570796",0],
  540.    ["ATAN","atan","atan(1)","0.785398",0],
  541.    ["ATAN2","atan2","atan2(1,0)","1.570796",0],
  542.    ["CEILING","ceiling","ceiling(-4.5)",-4,0],
  543.    ["COS","cos","cos(0)","1.00000",0],
  544.    ["COT","cot","cot(1)","0.64209262",0],
  545.    ["DEGREES","degrees","degrees(6.283185)","360",0],
  546.    ["EXP","exp","exp(1)","2.718282",0],
  547.    ["FLOOR","floor","floor(2.5)","2",0],
  548.    ["LOG","log","log(2)","0.693147",0],
  549.    ["LOG10","log10","log10(10)","1",0],
  550.    ["MOD","mod","mod(11,7)","4",0],
  551.    ["PI","pi","pi()","3.141593",0],
  552.    ["POWER","power","power(2,4)","16",0],
  553.    ["RAND","rand","rand(1)",0,2],       # Any value is acceptable
  554.    ["RADIANS","radians","radians(360)","6.283185",0],
  555.    ["ROUND(2 arg)","round","round(5.63,2)","5.6",0],
  556.    ["SIGN","sign","sign(-5)",-1,0],
  557.    ["SIN","sin","sin(1)","0.841471",0],
  558.    ["SQRT","sqrt","sqrt(4)",2,0],
  559.    ["TAN","tan","tan(1)","1.557408",0],
  560.    ["TRUNCATE","truncate","truncate(18.18,-1)",10,0],
  561.    ["NOW","now","now()",0,2],           # Any value is acceptable
  562.    ["CURDATE","curdate","curdate()",0,2],
  563.    ["DAYNAME","dayname","dayname(DATE '1997-02-01')","",2],
  564.    ["MONTH","month","month(DATE '1997-02-01')","",2],
  565.    ["MONTHNAME","monthname","monthname(DATE '1997-02-01')","",2],
  566.    ["DAYOFMONTH","dayofmonth","dayofmonth(DATE '1997-01-02')",2,0],
  567.    ["DAYOFWEEK","dayofweek","dayofweek(DATE '1997-01-02')",5,0],
  568.    ["DAYOFYEAR","dayofyear","dayofyear(DATE '1997-02-01')",32,0],
  569.    ["EXTRACT","extract","extract(YEAR from '1997-02-01')","",2],
  570.    ["QUARTER","quarter","quarter(DATE '1997-01-02')",1,0],
  571.    ["WEEK","week","week(DATE '1997-01-01')",1,0],
  572.    ["YEAR","year","year(DATE '1997-01-02')",1997,0],
  573.    ["CURTIME","curtime","curtime()",0,2],
  574.    ["HOUR","hour","hour('12:13:14')",12,0],
  575.    ["ANSI HOUR","hour_time","hour(TIME '12:13:14')",12,0],
  576.    ["MINUTE","minute","minute('12:13:14')",13,0],
  577.    ["SECOND","second","second('12:13:14')",14,0],
  578.    ["TIMESTAMPADD","timestampadd",
  579.     "timestampadd(SQL_TSI_SECOND,1,DATE '1997-01-01 00:00:00')",
  580.     "1997-01-01 00:00:01",1],
  581.    ["TIMESTAMPDIFF","timestampdiff",
  582.     "timestampdiff(SQL_TSI_SECOND,DATE '1997-01-01 00:00:01', DATE '1997-01-01 00:00:01')","1",0],
  583.    ["USER()","user()","user()",0,2],
  584.    ["DATABASE","database","database()",0,2],
  585.    ["IFNULL","ifnull","ifnull(2,3)",2,0],
  586.    ["ODBC syntax LEFT & RIGHT", "fn_left",
  587.     "{ fn LEFT( { fn RIGHT('abcd',2) },1) }","c",1],
  588.    );
  589.  
  590. @extra_functions=
  591.   (["CONCAT(list)","concat_list", "concat('a','b','c','d')","abcd",1],
  592.    ["ENCRYPT","encrypt","encrypt('hello')",0,2],
  593.    ["MOD as %","%","10%7","3",0],
  594.    ["PASSWORD","password","password('hello')",0,2],
  595.    ["ROUND(1 arg)","round1","round(5.63)","6",0],
  596.    ["LOCATE as INSTR","instr","instr('hello','ll')",3,0],
  597.    ["SUBSTRING as MID","mid","mid('hello',3,2)","ll",1],
  598.    ["SUBSTRING_INDEX","substring_index","substring_index('www.tcx.se','.',-2)",
  599.     "tcx.se",1],
  600.    ["TRIM; Many char extension","trim_many_char","trim(':!' FROM ':abc!')","abc",3],
  601.    ["TRIM; Substring extension","trim_substring","trim('cb' FROM 'abccb')","abc",3],
  602.    ["automatic string->num convert","auto_string2num","'1'+2",3,0],
  603.    ["automatic num->string convert","auto_num2string","concat('a',2)","a2",1],
  604.    ["CONVERT","convert","convert(CHAR,5)","5",1],
  605.    ["ODBC CONVERT","odbc_convert","convert(5,SQL_CHAR)","5",1],
  606.    ["POW","pow","pow(3,2)",9,0],
  607.    ["=","=","(1=1)",1,$logical_value],
  608.    ["<> in SELECT","<>","1<>1","0",0],
  609.    ["& (bitwise and)",'&',"5 & 3",1,0],
  610.    ["| (bitwise or)",'|',"1 | 2",3,0],
  611.    ["<< and >> (bitwise shifts)",'binary_shifts',"(1 << 4) >> 2",4,0],
  612.    ["BIT_COUNT","bit_count","bit_count(5)",2,0],
  613.    ["LIKE in SELECT","like","'a' like 'a%'",$logical_value,0],
  614.    ["NOT LIKE in SELECT","not_like","'a' not like 'a%'",0,0],
  615.    ["LIKE ESCAPE in SELECT","like_escape","'%' like 'a%' escape 'a'",$logical_value,0],
  616.    ["REGEXP in SELECT","regexp","'a' regexp '^(a|b)*\$'",$logical_value,0],
  617.    ["AND and OR in SELECT","and_or","1=1 AND 2=2",$logical_value,0],
  618.    ["AND as '&&'",'&&',"1=1 && 2=2",$logical_value,0],
  619.    ["OR as '||'",'||',"1=0 || 1=1",$logical_value,0],
  620.    ["NOT in SELECT","not","not 0",$logical_value,0],
  621.    ["NOT as '!' in SELECT","!","! 1",0,0],
  622.    ["BETWEEN in SELECT","between","5 between 4 and 6",$logical_value,0],
  623.    ["NOT BETWEEN in SELECT","not_between","5 not between 4 and 6",0,0],
  624.    ["IN on numbers in SELECT","in_num","2 in (3,2,5,9,5,1)",$logical_value,0],
  625.    ["IN on strings in SELECT","in_str","'monty' in ('david','monty','allan')",
  626.     $logical_value,0],
  627.    ["IF","if", "if(5,6,7)",6,0],
  628.    ["INTERVAL","interval","interval(55,10,20,30,40,50,60,70,80,90,100)",5,0],
  629.    ["FIELD","field","field('IBM','NCA','ICL','SUN','IBM','DIGITAL')",4,0],
  630.    ["ELT","elt","elt(2,'ONE','TWO','THREE')","TWO",1],
  631.    ["FORMAT","format","format(1234.5555,2)","1,234.56",1],
  632.    ["STRCMP","strcmp","strcmp('abc','adc')",-1,0],
  633.    ["TO_DAYS","to_days","to_days(DATE '1996-01-01')",729024,0],
  634.    ["FROM_DAYS","from_days","from_days(729024)","1996-01-01",1],
  635.    ["WEEKDAY","weekday","weekday(DATE '1997-11-29')",5,0],
  636.    ["PERIOD_ADD","period_add","period_add(9602,-12)",199502,0],
  637.    ["PERIOD_DIFF","period_diff","period_diff(199505,199404)",13,0],
  638.    ["UNIX_TIMESTAMP","unix_timestamp","unix_timestamp()",0,2],
  639.    ["FROM_UNIXTIME","from_unixtime","from_unixtime(0)",0,2],
  640.    ["SEC_TO_TIME","sec_to_time","sec_to_time(5001)","01:23:21",1],
  641.    ["TIME_TO_SEC","time_to_sec","time_to_sec('01:23:21')","5001",0],
  642.    ["DATE_FORMAT","date_format",
  643.     "date_format('1997-01-02 03:04:05','M W D Y y m d h i s w')", 0,2],
  644.    ["LAST_INSERT_ID","last_insert_id","last_insert_id()",0,2],
  645.    ["VERSION","version","version()",0,2],
  646.    ["TRANSLATE","translate","translate('abc','bc','de')",'ade',3],
  647.    ["LPAD","lpad","lpad('hi',4,'??')",'??hi',3],
  648.    ["RPAD","rpad","rpad('hi',4,'??')",'hi??',3],
  649.    ["STR","str","str(123.45,5,1)",123.5,3],
  650.    ["STUFF","stuff","stuff('abc',2,3,'xyz')",'axyz',3],
  651.    ["concatenation with +","concat_as_+","'abc' + 'def'","abcdef",1],
  652.    ["GETDATE","getdate","getdate()",0,2],
  653.    ["DATEPART","datepart","datepart(month,'July 20 1997')",0,2],
  654.    ["DATEDIFF","datediff","datediff(month,'Oct 21 1997','Nov 30 1997')",0,2],
  655.    ["DATEADD","dateadd","dateadd(day,3,'Nov 30 1997')",0,2],
  656.    ["DATENAME","datename","datename(month,'Nov 30 1997')",0,2],
  657.    ["CHARINDEX","charindex","charindex('a','crash')",3,0],
  658.    ["PATINDEX","patindex","patindex('%a%','crash')",3,0],
  659.    ["REPLICATE","replicate","replicate('a',5)","aaaaa",1],
  660.    ["REVERSE","reverse","reverse('abcd')","dcba",1],
  661.    ["ATN2","atn2","atn2(1,0)","1.570796",0],
  662.    ["CEIL","ceil","ceil(-4.5)",-4,0], # oracle
  663.    ["COSH","cosh","cosh(0)","1",0], # oracle hyperbolic cosine of n.
  664.    ["LN","ln","ln(95)","4.55387689",0], # oracle natural logarithm of n
  665.    ["LOG(m,n)","log(m_n)","log(10,100)","2",0], # oracle logarithm, base m, of n
  666.    ["SINH","sinh","sinh(1)","1.17520119",0], # oracle hyperbolic sine of n
  667.    ["TANH","tanh","tanh(1)","0.462117157",0], # oracle hyperbolic tangent of n
  668.    ["TRUNC","trunc","trunc(18.18,-1)",10,0], # oracle
  669.    ["CHR", "chr", "CHR(65)"  ,"A",1], # oracle
  670.    ["INITCAP","initcap","initcap('the soap')","The Soap",1], # oracle Returns char, with the first letter of each word in uppercase
  671.    ["SUBSTRB", "substrb", "SUBSTRB('ABCDEFG',5,4.2)"  ,"CD",1], # oracle substring with bytes
  672.    ["INSTR", "instr", "INSTR('CORPORATE FLOOR','OR',3,2)"  ,"14",0], # oracle instring
  673.    ["INSTRB", "instrb", "INSTRB('CORPORATE FLOOR','OR',5,2)"  ,"27",0], # oracle instring in bytes
  674.    ["LENGTHB","lengthb","lengthb('CANDIDE')","14",0], # oracle length in bytes
  675.    ["ADD_MONTHS","add_months","add_months('1997-01-01',1)","1997-02-01",0], # oracle the date plus n months
  676.    ["LAST_DAY","last_day","last_day('1997-04-01')","1997-04-30",0], # oracle last day of month of date
  677.    ["MONTHS_BETWEEN","months_between","months_between('1997-02-02','1997-01-01')","1.03225806",0], # oracle number of months between 2 dates
  678.    ["GREATEST","greatest","greatest('HARRY','HARRIOT','HAROLD')","HARRY",1], # oracle
  679.    ["LEAST","least","least('HARRY','HARRIOT','HAROLD')","HAROLD",1], # oracle
  680.    ["UID","uid","uid",0,2], # oracle uid from user
  681.    ["USERENV","userenv","userenv",0,2], # oracle user enviroment
  682.    ["ROOT","root","root(4)",2,0], # informix
  683.    ["LOGN","logn","logn(2)","0.693147",0], # informix
  684.    ["MDY","mdy","mdy(7,1,1998)","1998-07-01",0], # informix
  685.    ["RANGE","range","range(a)","0.0",0], # informix range(a) = max(a) - min(a)
  686.    );
  687.  
  688. @sql_group_functions=
  689.   (["COUNT (*)","count_*","count(*)",1,0],
  690.    ["COUNT column name","count_column","count(a)",1,0],
  691.    ["COUNT DISTINCT column name","count_distinct","count(distinct a)",1,0],
  692.    ["SUM","sum","sum(a)",1,0],
  693.    ["AVG","avg","avg(a)",1,0],
  694.    ["MAX on numbers","max","max(a)",1,0],
  695.    ["MIN on numbers","min","min(a)",1,0],
  696.    ["MAX on strings","max_str","max(b)","a",1],
  697.    ["MIN on strings","min_str","min(b)","a",1],
  698.    );
  699.  
  700. @extra_group_functions=
  701.   (["STD","std","std(a)",0,0],
  702.    ["STDDEV","stddev","stddev(a)",0,0],
  703.    ["BIT_OR", 'bit_or', "bit_or(a)",1,0],
  704.    ["BIT_AND",'bit_and',"bit_and(a)",1,0],
  705.    ["VARIANCE","variance","variance(a)",0,0],
  706.    );
  707.  
  708. @where_functions=
  709. (["LIKE","like","b like 'a%'",1,0],
  710.  ["NOT LIKE","not_like","b not like 'b%'",1,0],
  711.  ["LIKE ESCAPE","like_escape","b like '%' escape 'a'",1,0],
  712.  ["MATCHES","matches","b matcjhes 'a*'",1,0],
  713.  ["IN on numbers","in_num","2 in (3,2,5,9,5,1)",1,0],
  714.  ["BETWEEN","between","5 between 4 and 6",1,0],
  715.  ["NOT BETWEEN","not_between","7 not between 4 and 6",1,0],
  716.  ["MATCH","match","1 match (select a from crash_me)",1,0],
  717.  ["MATCH UNIQUE","match_unique","1 match unique (select a from crash_me)",1,0],
  718.  ["= ALL","eq_all","b =all (select b from crash_me)",1,0],
  719.  ["= ANY","eq_any","b =any (select b from crash_me)",1,0],
  720.  ["= SOME","eq_some","b =some (select b from crash_me)",1,0],
  721.  ["EXISTS","exists","exists (select * from crash_me)",1,0],
  722.  ["NOT EXISTS","not_exists","not exists (select * from crash_me where a = 2)",1,0],
  723.  ["UNIQUE","unique","unique (select * from crash_me)",1,0],
  724.  ["NOT UNIQUE","not_unique","not unique (select * from crash_me where a = 2)",1,0],
  725.  );
  726.  
  727. @types=(["sql",\@sql_functions,0],
  728.     ["odbc",\@odbc_functions,0],
  729.     ["extra",\@extra_functions,0],
  730.     ["where",\@where_functions,0]);
  731.  
  732. @group_types=(["sql",\@sql_group_functions,0],
  733.           ["extra",\@extra_group_functions,0]);
  734.  
  735.  
  736. foreach $types (@types)
  737. {
  738.   print "\nSupported $types->[0] functions\n";
  739.   $tmp=@$types->[1];
  740.   foreach $type (@$tmp)
  741.   {
  742.     if ($types->[0] eq "where")
  743.     {
  744.       check_and_report("Function $type->[0]","func_$types->[0]_$type->[1]",
  745.                [],"select a from crash_me where $type->[2]",[],
  746.                $type->[3],$type->[4]);
  747.     }
  748.     elsif ($limits{'functions'} eq 'yes')
  749.     {
  750.       if (!check_and_report("Function $type->[0]",
  751.                 "func_$types->[0]_$type->[1]",
  752.                 [],"select $type->[2] $end_query",[],
  753.                 $type->[3],$type->[4]))
  754.       {
  755.     # check without type specifyer
  756.     if ($type->[2] =~ /DATE /)
  757.     {
  758.       my $tmp= $type->[2];
  759.       $tmp =~ s/DATE //;
  760.       undef($limits{"func_$types->[0]_$type->[1]"});
  761.       check_and_report("Function $type->[0]",
  762.                "func_$types->[0]_$type->[1]",
  763.                [],"select $tmp $end_query",[],
  764.                $type->[3],$type->[4]);
  765.     }
  766.       }
  767.     }
  768.   }
  769. }
  770.  
  771. if ($limits{'functions'} eq 'yes')
  772. {
  773.   foreach $types (@group_types)
  774.   {
  775.     print "\nSupported $types->[0] group functions\n";
  776.     $tmp=@$types->[1];
  777.     foreach $type (@$tmp)
  778.     {
  779.       check_and_report("Group function $type->[0]",
  780.                "group_func_$types->[0]_$type->[1]",
  781.                [],"select $type->[2],a from crash_me group by a",[],
  782.                $type->[3],$type->[4]);
  783.     }
  784.   }
  785.   print "\n";
  786.   report("mixing of integer and float in expression","float_int_expr",
  787.      "select 1+1.0 $end_query");
  788.  
  789.   check_and_report("Is 1+NULL = NULL","null_num_expr",
  790.            [],"select 1+NULL $end_query",[],undef(),4);
  791.   $tmp=sql_concat("'a'","NULL");
  792.   if (defined($tmp))
  793.   {
  794.     check_and_report("Is $tmp = NULL", "null_concat_expr", [],
  795.              "select $tmp $end_query",[], undef(),4);
  796.   }
  797. }
  798. else
  799. {
  800.   print "\n";
  801. }
  802.  
  803.  
  804. report("LIKE on numbers","like_with_number",
  805.        "create table crash_q (a int,b int)",
  806.        "insert into crash_q values(10,10)",
  807.        "select * from crash_q where a like '10'",
  808.        "drop table crash_q");
  809.  
  810. report("column LIKE column","like_with_column",
  811.        "create table crash_q (a char(10),b char(10))",
  812.        "insert into crash_q values('abc','abc')",
  813.        "select * from crash_q where a like b",
  814.        "drop table crash_q");
  815.  
  816. report("update of column= -column","NEG",
  817.        "create table crash_q (a integer)",
  818.        "insert into crash_q values(10)",
  819.        "update crash_q set a=-a",
  820.        "drop table crash_q");
  821.  
  822. if ($limits{'func_odbc_left'} eq 'yes' ||
  823.     $limits{'func_odbc_substring'} eq 'yes')
  824. {
  825.   my $type= ($limits{'func_odbc_left'} eq 'yes' ?
  826.          "left(a,4)" : "substring(a,1,4)");
  827.  
  828.     check_and_report("String functions on date columns","date_as_string",
  829.              ["create table crash_me2 (a date not null)",
  830.               "insert into crash_me2 values ('1998-03-03')"],
  831.              "select $type from crash_me2",
  832.              ["drop table crash_me2"],
  833.              "1998",1);
  834. }
  835.  
  836.  
  837. $tmp=sql_concat("b","b");
  838. if (defined($tmp))
  839. {
  840.   check_and_report("char are space filled","char_is_space_filled",
  841.            [],"select $tmp from crash_me",[],
  842.            'b         b         ',6);
  843. }
  844.  
  845. if (!defined($limits{'multi_table_update'}))
  846. {
  847.   if (check_and_report("Update with many tables","multi_table_update",
  848.            ["create table crash_q (a integer,b char(10))",
  849.             "insert into crash_q values(1,'c')",
  850.             "update crash_q left join crash_me on crash_q.a=crash_me.a set crash_q.b=crash_me.b"],
  851.            "select b from crash_q",
  852.            ["drop table crash_q"],
  853.            "a",1,undef(),2))
  854.   {
  855.     check_and_report("Update with many tables","multi_table_update",
  856.              ["create table crash_q (a integer,b char(10))",
  857.               "insert into crash_q values(1,'c')",
  858.               "update crash_q,crash_me set crash_q.b=crash_me.b where crash_q.a=crash_me.a"],
  859.              "select b from crash_q",
  860.              ["drop table crash_q"],
  861.              "a",1,
  862.             1);
  863.   }
  864. }
  865.  
  866. report("DELETE FROM table1,table2...","multi_table_delete",
  867.        "create table crash_q (a integer,b char(10))",
  868.        "insert into crash_q values(1,'c')",
  869.        "delete crash_q from crashq,crash_me where crash_q.a=crash_me.a",
  870.        "drop table crash_q");
  871.  
  872. check_and_report("Update with sub select","select_table_update",
  873.          ["create table crash_q (a integer,b char(10))",
  874.           "insert into crash_q values(1,'c')",
  875.           "update crash_q set crash_q.b= (select b from crash_me where crash_q.a = crash_me.a)"],
  876.          "select b from crash_q",
  877.          ["drop table crash_q"],
  878.          "a",1);
  879.  
  880. check_and_report("Calculate 1--1","minus_neg",[],
  881.          "select a--1 from crash_me",[],0,2);
  882.  
  883. report("ANSI SQL simple joins","simple_joins",
  884.        "select crash_me.a from crash_me, crash_me t0");
  885.  
  886. #
  887. # Check max string size, and expression limits
  888. #
  889.  
  890. find_limit(($prompt="constant string size in where"),"where_string_size",
  891.        new query_repeat([],"select a from crash_me where b <'",
  892.                 "","","a","","'"));
  893. if ($limits{'where_string_size'} == 10)
  894. {
  895.   save_config_data('where_string_size','nonstandard',$prompt);
  896. }
  897.  
  898. if ($limits{'select_constants'} eq 'yes')
  899. {
  900.   find_limit("constant string size in SELECT","select_string_size",
  901.          new query_repeat([],"select '","","","a","","'$end_query"));
  902. }
  903.  
  904. goto no_functions if ($limits{'functions'} ne "yes");
  905.  
  906. if ($limits{'func_odbc_repeat'} eq 'yes')
  907. {
  908.   find_limit("return string size from function","repeat_string_size",
  909.          new query_many([],
  910.                 "select repeat('a',%d) $end_query","%s",
  911.                 [],
  912.                 $max_string_size,0));
  913. }
  914.  
  915. $tmp=find_limit("simple expressions","max_expressions",
  916.         new query_repeat([],"select 1","","","+1","",$end_query));
  917.  
  918. if ($tmp > 10)
  919. {
  920.   $tmp= "(1" . ( '+1' x ($tmp-10) ) . ")";
  921.   find_limit("big expressions", "max_big_expressions",
  922.          new query_repeat([],"select 0","","","+$tmp","",$end_query));
  923. }
  924.  
  925. find_limit("stacked expressions", "max_stack_expression",
  926.        new query_repeat([],"select 1","","","+(1",")",$end_query));
  927.  
  928. no_functions:
  929.  
  930. if (!defined($limits{'max_conditions'}))
  931. {
  932.   find_limit("OR and AND in WHERE","max_conditions",
  933.          new query_repeat([],
  934.                   "select a from crash_me where a=1 and b='a'","",
  935.                   "", " or a=%d and b='%d'","","","",
  936.                   [],($query_size-42)/19,undef,2));
  937.   $limits{'max_conditions'}*=2;
  938. }
  939.  
  940. find_limit("tables in join", "join_tables",
  941.        new query_repeat([],
  942.                 "select crash_me.a",",t%d.a","from crash_me",
  943.                 ",crash_me t%d","","",[],$max_join_tables,undef,
  944.                 1));
  945.  
  946. report("primary key in create table",'primary_key_in_create',
  947.        "create table crash_q (q integer not null,primary key (q))",
  948.        "drop table crash_q");
  949.  
  950. report("unique in create table",'unique_in_create',
  951.        "create table crash_q (q integer not null,unique (q))",
  952.        "drop table crash_q");
  953.  
  954. if ($limits{'unique_in_create'} eq 'yes')
  955. {
  956.   report("unique null in create",'unique_null_in_create',
  957.      "create table crash_q (q integer,unique (q))",
  958.      "insert into crash_q (q) values (NULL)",
  959.      "insert into crash_q (q) values (NULL)",
  960.      "insert into crash_q (q) values (1)",
  961.      "drop table crash_q");
  962. }
  963.  
  964. report("index in create table",'index_in_create',
  965.        "create table crash_q (q integer not null,index (q))",
  966.        "drop table crash_q");
  967.  
  968. if (!defined($limits{'create_index'}))
  969. {
  970.   if ($res=safe_query("create index crash_q on crash_me (a)"))
  971.   {
  972.     $res="yes";
  973.     $drop_res="yes";
  974.     $end_drop_keyword="";
  975.     if (!safe_query("drop index crash_q"))
  976.     {
  977.       # Can't drop the standard way; Check if mSQL
  978.       if (safe_query("drop index crash_q from crash_me"))
  979.       {
  980.     $drop_res="with 'FROM'";        # Drop is not ANSI SQL
  981.     $end_drop_keyword="drop index %i from %t";
  982.       }
  983.       # else check if Access or MySQL
  984.       elsif (safe_query("drop index crash_q on crash_me"))
  985.       {
  986.     $drop_res="with 'ON'";          # Drop is not ANSI SQL
  987.     $end_drop_keyword="drop index %i on %t";
  988.       }
  989.       # else check if MS-SQL
  990.       elsif (safe_query("drop index crash_me.crash_q"))
  991.       {
  992.     $drop_res="with 'table.index'";          # Drop is not ANSI SQL
  993.     $end_drop_keyword="drop index %t.%i";
  994.       }
  995.     }
  996.     else
  997.     {
  998.       # Old MySQL 3.21 supports only the create index syntax
  999.       # This means that the second create doesn't give an error.
  1000.       $res=safe_query(["create index crash_q on crash_me (a)",
  1001.                "create index crash_q on crash_me (a)",
  1002.                "drop index crash_q"]);
  1003.       $res= $res ? 'ignored' : 'yes';
  1004.     }
  1005.   }
  1006.   else
  1007.   {
  1008.     $drop_res=$res='no';
  1009.   }
  1010.   save_config_data('create_index',$res,"create index");
  1011.   save_config_data('drop_index',$drop_res,"drop index");
  1012. }
  1013.  
  1014. print "create index: $limits{'create_index'}\n";
  1015. print "drop index: $limits{'drop_index'}\n";
  1016.  
  1017. report("default value for column",'create_default',
  1018.        "create table crash_q (q integer not null default 10)",
  1019.        "drop table crash_q");
  1020.  
  1021. # check if we can have 'NULL' as a key
  1022. if ($limits{'index_in_create'} eq 'yes')
  1023. {
  1024.   $tmp=["create table crash_q (a char(10),index (a))",
  1025.     "insert into crash_q values (NULL)"];
  1026. }
  1027. else
  1028. {
  1029.   $tmp=["create table crash_q (a char(10))",
  1030.     "create index crash_q_index on crash_q (a)",
  1031.     "insert into crash_q values (NULL)"];
  1032. }
  1033. check_and_report("null in index","null_in_index",
  1034.          $tmp,
  1035.          "select * from crash_q",
  1036.          ["drop table crash_q"],
  1037.          undef(),4);
  1038.  
  1039. if ($limits{'unique_in_create'} eq 'yes')
  1040. {
  1041.   report("null in unique",'null_in_unique',
  1042.      "create table crash_q (q integer,unique (q))",
  1043.      "drop table crash_q");
  1044. }
  1045.  
  1046.  
  1047.  
  1048. if ($limits{'create_index'} ne 'no')
  1049. {
  1050.   $end_drop=$end_drop_keyword;
  1051.   $end_drop =~ s/%i/crash_q/;
  1052.   $end_drop =~ s/%t/crash_me/;
  1053.   report("index on column part (extension)","index_parts",,
  1054.      "create index crash_q on crash_me (b(5))",
  1055.      $end_drop);
  1056.   $end_drop=$end_drop_keyword;
  1057.   $end_drop =~ s/%i/crash_me/;
  1058.   $end_drop =~ s/%t/crash_me/;
  1059.   report("different namespace for index",
  1060.      "index_namespace",
  1061.      "create index crash_me on crash_me (b)",
  1062.      $end_drop);
  1063. }
  1064.  
  1065. if (!report("case independent table names","table_name_case",
  1066.         "create table crash_q (q integer)",
  1067.         "drop table CRASH_Q"))
  1068. {
  1069.   safe_query("drop table crash_q");
  1070. }
  1071.  
  1072. #
  1073. # test name limits
  1074. #
  1075.  
  1076. find_limit("table name length","max_table_name",
  1077.        new query_many(["create table crash_q%s (q integer)",
  1078.                "insert into crash_q%s values(1)"],
  1079.                "select * from crash_q%s",1,
  1080.                ["drop table crash_q%s"],
  1081.                $max_name_length,7,1));
  1082.  
  1083. find_limit("column name length","max_column_name",
  1084.        new query_many(["create table crash_q (q%s integer)",
  1085.               "insert into crash_q (q%s) values(1)"],
  1086.               "select q%s from crash_q",1,
  1087.               ["drop table crash_q"],
  1088.                $max_name_length,1));
  1089.  
  1090. if ($limits{'column_alias'} eq 'yes')
  1091. {
  1092.   find_limit("select alias name length","max_select_alias_name",
  1093.        new query_many(undef,
  1094.               "select b as %s from crash_me",undef,
  1095.               undef, $max_name_length));
  1096. }
  1097.  
  1098. find_limit("table alias name length","max_table_alias_name",
  1099.        new query_many(undef,
  1100.               "select %s.b from crash_me %s",
  1101.               undef,
  1102.               undef, $max_name_length));
  1103.  
  1104. $end_drop_keyword = "drop index %i" if (!$end_drop_keyword);
  1105. $end_drop=$end_drop_keyword;
  1106. $end_drop =~ s/%i/crash_q%s/;
  1107. $end_drop =~ s/%t/crash_me/;
  1108.  
  1109. if ($limits{'create_index'} ne 'no')
  1110. {
  1111.   find_limit("index name length","max_index_name",
  1112.          new query_many(["create index crash_q%s on crash_me (a)"],
  1113.                 undef,undef,
  1114.                 [$end_drop],
  1115.                 $max_name_length,7));
  1116. }
  1117.  
  1118. find_limit("max char() size","max_char_size",
  1119.        new query_many(["create table crash_q (q char(%d))",
  1120.                "insert into crash_q values ('%s')"],
  1121.               "select * from crash_q","%s",
  1122.               ["drop table crash_q"],
  1123.               min($max_string_size,$limits{'query_size'})));
  1124.  
  1125. if ($limits{'type_sql_varchar()'} eq 'yes')
  1126. {
  1127.   find_limit("max varchar() size","max_varchar_size",
  1128.          new query_many(["create table crash_q (q varchar(%d))",
  1129.                  "insert into crash_q values ('%s')"],
  1130.                 "select * from crash_q","%s",
  1131.                 ["drop table crash_q"],
  1132.                 min($max_string_size,$limits{'query_size'})));
  1133. }
  1134.  
  1135. $found=undef;
  1136. foreach $type (('mediumtext','text','text()','blob','long'))
  1137. {
  1138.   if ($limits{"type_extra_$type"} eq 'yes')
  1139.   {
  1140.     $found=$type;
  1141.     last;
  1142.   }
  1143. }
  1144. if (defined($found))
  1145. {
  1146.   $found =~ s/\(\)/\(%d\)/;
  1147.   find_limit("max text or blob size","max_text_size",
  1148.          new query_many(["create table crash_q (q $found)",
  1149.                  "insert into crash_q values ('%s')"],
  1150.                 "select * from crash_q","%s",
  1151.                 ["drop table crash_q"],
  1152.                 min($max_string_size,$limits{'query_size'}-30)));
  1153.  
  1154. }
  1155.  
  1156. $tmp=new query_repeat([],"create table crash_q (a integer","","",
  1157.               ",a%d integer","",")",["drop table crash_q"],
  1158.               $max_columns);
  1159. $tmp->{'offset'}=1;
  1160. find_limit("Columns in table","max_columns",$tmp);
  1161.  
  1162. # Make a field definition to be used when testing keys
  1163.  
  1164. $key_definitions="q0 integer not null";
  1165. $key_fields="q0";
  1166. for ($i=1; $i < min($limits{'max_columns'},$max_keys) ; $i++)
  1167. {
  1168.   $key_definitions.=",q$i integer not null";
  1169.   $key_fields.=",q$i";
  1170. }
  1171. $key_values="1," x $i;
  1172. chop($key_values);
  1173.  
  1174. if ($limits{'unique_in_create'} eq 'yes')
  1175. {
  1176.   find_limit("unique indexes","max_unique_index",
  1177.          new query_table("create table crash_q (q integer",
  1178.                  ",q%d integer not null,unique (q%d)",")",
  1179.                  ["insert into crash_q (q,%f) values (1,%v)"],
  1180.                  "select q from crash_q",1,
  1181.                  "drop table crash_q",
  1182.                  $max_keys,0));
  1183.  
  1184.   find_limit("index parts","max_index_parts",
  1185.          new query_table("create table crash_q ($key_definitions,unique (q0",
  1186.                  ",q%d","))",
  1187.                  ["insert into crash_q ($key_fields) values ($key_values)"],
  1188.                  "select q0 from crash_q",1,
  1189.                  "drop table crash_q",
  1190.                  $max_keys,0));
  1191.  
  1192.   find_limit("max index part length","max_index_part_length",
  1193.          new query_many(["create table crash_q (q char(%d) not null,unique(q))",
  1194.                  "insert into crash_q (q) values ('%s')"],
  1195.                 "select q from crash_q","%s",
  1196.                 ["drop table crash_q"],
  1197.                 $limits{'max_char_size'},0));
  1198.  
  1199.   if ($limits{'type_sql_varchar()'} eq 'yes')
  1200.   {
  1201.     find_limit("index varchar part length","max_index_varchar_part_length",
  1202.          new query_many(["create table crash_q (q varchar(%d) not null,unique(q))",
  1203.                  "insert into crash_q (q) values ('%s')"],
  1204.                 "select q from crash_q","%s",
  1205.                 ["drop table crash_q"],
  1206.                 $limits{'max_varchar_size'},0));
  1207.   }
  1208. }
  1209.  
  1210.  
  1211. if ($limits{'create_index'} ne 'no')
  1212. {
  1213.   if ($limits{'create_index'} eq 'ignored' ||
  1214.       $limits{'unique_in_create'} eq 'yes')
  1215.   {                                     # This should be true
  1216.     save_config_data('max_index',$limits{'max_unique_index'},"max index");
  1217.     print "indexes: $limits{'max_index'}\n";
  1218.   }
  1219.   else
  1220.   {
  1221.     if (!defined($limits{'max_index'}))
  1222.     {
  1223.       assert("create table crash_q ($key_definitions)");
  1224.       for ($i=1; $i <= min($limits{'max_columns'},$max_keys) ; $i++)
  1225.       {
  1226.     last if (!safe_query("create index crash_q$i on crash_q (q$i)"));
  1227.       }
  1228.       save_config_data('max_index',$i == $max_keys ? $max_keys : $i,
  1229.                "max index");
  1230.       while ( --$i > 0)
  1231.       {
  1232.     $end_drop=$end_drop_keyword;
  1233.     $end_drop =~ s/%i/crash_q$i/;
  1234.     $end_drop =~ s/%t/crash_q/;
  1235.     assert($end_drop);
  1236.       }
  1237.       assert("drop table crash_q");
  1238.     }
  1239.     print "indexs: $limits{'max_index'}\n";
  1240.     if (!defined($limits{'max_unique_index'}))
  1241.     {
  1242.       assert("create table crash_q ($key_definitions)");
  1243.       for ($i=0; $i < min($limits{'max_columns'},$max_keys) ; $i++)
  1244.       {
  1245.     last if (!safe_query("create unique index crash_q$i on crash_q (q$i)"));
  1246.       }
  1247.       save_config_data('max_unique_index',$i == $max_keys ? $max_keys : $i,
  1248.                "max unique index");
  1249.       while ( --$i >= 0)
  1250.       {
  1251.     $end_drop=$end_drop_keyword;
  1252.     $end_drop =~ s/%i/crash_q$i/;
  1253.     $end_drop =~ s/%t/crash_q/;
  1254.     assert($end_drop);
  1255.       }
  1256.       assert("drop table crash_q");
  1257.     }
  1258.     print "unique indexes: $limits{'max_unique_index'}\n";
  1259.     if (!defined($limits{'max_index_parts'}))
  1260.     {
  1261.       assert("create table crash_q ($key_definitions)");
  1262.       $end_drop=$end_drop_keyword;
  1263.       $end_drop =~ s/%i/crash_q1%d/;
  1264.       $end_drop =~ s/%t/crash_q/;
  1265.       find_limit("index parts","max_index_parts",
  1266.          new query_table("create index crash_q1%d on crash_q (q0",
  1267.                  ",q%d",")",
  1268.                  [],
  1269.                  undef,undef,
  1270.                  $end_drop,
  1271.                  $max_keys,1));
  1272.       assert("drop table crash_q");
  1273.     }
  1274.     else
  1275.     {
  1276.       print "index parts: $limits{'max_index_parts'}\n";
  1277.     }
  1278.     $end_drop=$end_drop_keyword;
  1279.     $end_drop =~ s/%i/crash_q2%d/;
  1280.     $end_drop =~ s/%t/crash_me/;
  1281.  
  1282.     find_limit("index part length","max_index_part_length",
  1283.            new query_many(["create table crash_q (q char(%d))",
  1284.                    "create index crash_q2%d on crash_q (q)",
  1285.                    "insert into crash_q values('%s')"],
  1286.                   "select q from crash_q",
  1287.                   "%s",
  1288.                   [ $end_drop,
  1289.                    "drop table crash_q"],
  1290.                   min($limits{'max_char_size'},"+8192")));
  1291.   }
  1292. }
  1293.  
  1294. find_limit("index length","max_index_length",
  1295.        new query_index_length("create table crash_q ",
  1296.                   "drop table crash_q",
  1297.                   $max_key_length));
  1298.  
  1299. find_limit("max table row length (without blobs)","max_row_length",
  1300.        new query_row_length("crash_q ",
  1301.                 "not null",
  1302.                 "drop table crash_q",
  1303.                 min($max_row_length,
  1304.                     $limits{'max_columns'}*
  1305.                     min($limits{'max_char_size'},255))));
  1306.  
  1307. find_limit("table row length with nulls (without blobs)",
  1308.        "max_row_length_with_null",
  1309.        new query_row_length("crash_q ",
  1310.                 "",
  1311.                 "drop table crash_q",
  1312.                 $limits{'max_row_length'}*2));
  1313.  
  1314. find_limit("number of columns in order by","columns_in_order_by",
  1315.        new query_many(["create table crash_q (%F)",
  1316.                "insert into crash_q values(%v)",
  1317.                "insert into crash_q values(%v)"],
  1318.               "select * from crash_q order by %f",
  1319.               undef(),
  1320.               ["drop table crash_q"],
  1321.               $max_order_by));
  1322.  
  1323. find_limit("number of columns in group by","columns_in_group_by",
  1324.        new query_many(["create table crash_q (%F)",
  1325.                "insert into crash_q values(%v)",
  1326.                "insert into crash_q values(%v)"],
  1327.               "select * from crash_q group by %f",
  1328.               undef(),
  1329.               ["drop table crash_q"],
  1330.               $max_order_by));
  1331.  
  1332. #
  1333. # test of differnt join types
  1334. #
  1335.  
  1336. assert("create table crash_me2 (a integer not null,b char(10) not null)");
  1337. assert("insert into crash_me2 (a,b) values (1,'b')");
  1338.  
  1339. report("left outer join","left_outer_join",
  1340.        "select crash_me.a from crash_me left join crash_me2 ON crash_me.a=crash_me2.a");
  1341. report("natural left outer join","natural_left_outer_join",
  1342.        "select crash_me.a from crash_me natural left join crash_me2");
  1343. report("left outer join using","left_outer_join_using",
  1344.        "select crash_me.a from crash_me left join crash_me2 using (a)");
  1345. report("left outer join odbc style","odbc_left_outer_join",
  1346.        "select crash_me.a from { oj crash_me left outer join crash_me2 ON crash_me.a=crash_me2.a }");
  1347. report("right outer join","right_outer_join",
  1348.        "select crash_me.a from crash_me right join crash_me2 ON crash_me.a=crash_me2.a");
  1349. report("full outer join","full_outer_join",
  1350.        "select crash_me.a from crash_me full join crash_me2 ON crash_me.a=crash_me2.a");
  1351. report("cross join (same as from a,b)","cross_join",
  1352.        "select crash_me.a from crash_me cross join crash_me2");
  1353. report("natural join","natural_join",
  1354.        "select crash_me.a from crash_me natural join crash_me2");
  1355. report("union","union",
  1356.        "select * from crash_me union select * from crash_me2");
  1357. report("union all","union_all",
  1358.        "select * from crash_me union all select * from crash_me2");
  1359. report("intersect","intersect",
  1360.        "select * from crash_me intersect select * from crash_me2");
  1361. report("intersect all","intersect_all",
  1362.        "select * from crash_me intersect all select * from crash_me2");
  1363. report("except","except",
  1364.        "select * from crash_me except select * from crash_me2");
  1365. report("except all","except_all",
  1366.        "select * from crash_me except all select * from crash_me2");
  1367. report("minus","minus",
  1368.        "select * from crash_me minus select * from crash_me2"); # oracle ...
  1369.  
  1370. assert("drop table crash_me2");
  1371.  
  1372. # somethings to be added here ....
  1373. # FOR UNION - INTERSECT - EXCEPT -> CORRESPONDING [ BY ]
  1374. # after subqueries:
  1375. # >ALL | ANY | SOME - EXISTS - UNIQUE
  1376.  
  1377. if (report("subqueries","subqueries",
  1378.        "select a from crash_me where crash_me.a in (select max(a) from crash_me)"))
  1379. {
  1380.     $tmp=new query_repeat([],"select a from crash_me","","",
  1381.               " where a in (select a from crash_me",")",
  1382.               "","",[],$max_join_tables);
  1383.     find_limit("recursive subqueries", "recursive_subqueries",$tmp);
  1384. }
  1385.  
  1386. report("insert INTO ... SELECT ...","insert_select",
  1387.        "create table crash_q (a int)",
  1388.        "insert into crash_q (a) SELECT crash_me.a from crash_me",
  1389.        "drop table crash_q");
  1390.  
  1391. report_trans("transactions","transactions",
  1392.        [create_table("crash_q",["a integer not null"],[]),
  1393.        "insert into crash_q values (1)"],
  1394.        "select * from crash_q",
  1395.        "drop table crash_q"
  1396.        );
  1397.  
  1398. report("atomic updates","atomic_updates",
  1399.        create_table("crash_q",["a integer not null"],["primary key (a)"]),
  1400.        "insert into crash_q values (2)",
  1401.        "insert into crash_q values (3)",
  1402.        "insert into crash_q values (1)",
  1403.        "update crash_q set a=a+1",
  1404.        "drop table crash_q");
  1405.  
  1406. if ($limits{'atomic_updates'} eq 'yes')
  1407. {
  1408.   report_fail("atomic_updates_with_rollback","atomic_updates_with_rollback",
  1409.           create_table("crash_q",["a integer not null"],
  1410.                ["primary key (a)"]),
  1411.           "insert into crash_q values (2)",
  1412.           "insert into crash_q values (3)",
  1413.           "insert into crash_q values (1)",
  1414.           "update crash_q set a=a+1 where a < 3",
  1415.           "drop table crash_q");
  1416. }
  1417.  
  1418. # To add with the views:
  1419. # DROP VIEW - CREAT VIEW *** [ WITH [ CASCADE | LOCAL ] CHECK OPTION ]
  1420. report("views","views",
  1421.        "create view crash_q as select a from crash_me",
  1422.        "drop view crash_q");
  1423.  
  1424. report("foreign key syntax","foreign_key_syntax",
  1425.        create_table("crash_q",["a integer not null"],["primary key (a)"]),
  1426.        create_table("crash_q2",["a integer not null",
  1427.                 "foreign key (a) references crash_q (a)"],
  1428.             []),
  1429.        "insert into crash_q values (1)",
  1430.        "insert into crash_q2 values (1)",
  1431.        "drop table crash_q2",
  1432.        "drop table crash_q");
  1433.  
  1434. if ($limits{'foreign_key_syntax'} eq 'yes')
  1435. {
  1436.   report_fail("foreign keys","foreign_key",
  1437.           create_table("crash_q",["a integer not null"],
  1438.                ["primary key (a)"]),
  1439.           create_table("crash_q2",["a integer not null",
  1440.                        "foreign key (a) references crash_q (a)"],
  1441.                []),
  1442.           "insert into crash_q values (1)",
  1443.           "insert into crash_q2 values (2)",
  1444.           "drop table crash_q2",
  1445.           "drop table crash_q");
  1446. }
  1447.  
  1448. if (!defined($limits{'lock_tables'}))
  1449. {
  1450.   report("lock table","lock_tables",
  1451.      "lock table crash_me READ",
  1452.      "unlock tables");
  1453.   if ($limits{'lock_tables'} eq 'no')
  1454.   {
  1455.     delete $limits{'lock_tables'};
  1456.     report("lock table","lock_tables",
  1457.        "lock table crash_me IN SHARE MODE");
  1458.   }
  1459. }
  1460.  
  1461. if (!report("many tables to drop table","multi_drop",
  1462.        "create table crash_q (a int)",
  1463.        "create table crash_q2 (a int)",
  1464.        "drop table crash_q,crash_q2"))
  1465. {
  1466.   $dbh->do("drop table crash_q");
  1467.   $dbh->do("drop table crash_q2");
  1468. }
  1469.  
  1470.  
  1471. report("-- as comment","comment_--",
  1472.        "select * from crash_me -- Testing of comments");
  1473. report("# as comment","comment_#",
  1474.        "select * from crash_me # Testing of comments");
  1475. report("/* */ as comment","comment_/**/",
  1476.        "select * from crash_me /* Testing of comments */");
  1477.  
  1478. #
  1479. # Check things that fails one some servers
  1480. #
  1481.  
  1482. # Empress can't insert empty strings in a char() field
  1483. report("insert empty string","insert_empty_string",
  1484.        create_table("crash_q",["a char(10) not null,b char(10)"],[]),
  1485.        "insert into crash_q values ('','')",
  1486.        "drop table crash_q");
  1487.  
  1488. report("Having with alias","having_with_alias",
  1489.        create_table("crash_q",["a integer"],[]),
  1490.        "insert into crash_q values (10)",
  1491.        "select sum(a) as b from crash_q group by a having b > 0",
  1492.        "drop table crash_q");
  1493.  
  1494. #
  1495. # End of test
  1496. #
  1497.  
  1498. $dbh->do("drop table crash_me");        # Remove temporary table
  1499.  
  1500. print "crash-me safe: $limits{'crash_me_safe'}\n";
  1501. print "reconnected $reconnect_count times\n";
  1502.  
  1503. $dbh->disconnect;
  1504. save_all_config_data();
  1505. exit 0;
  1506.  
  1507. sub usage
  1508. {
  1509.     print <<EOF;
  1510. $0  Ver $version
  1511.  
  1512. This program tries to find all limits and capabilities for a SQL
  1513. server.  As it will use the server in some 'unexpected' ways, one
  1514. shouldn\'t have anything important running on it at the same time this
  1515. program runs!  There is a slight chance that something unexpected may
  1516. happen....
  1517.  
  1518. As all used queries are legal according to some SQL standard. any
  1519. reasonable SQL server should be able to run this test without any
  1520. problems.
  1521.  
  1522. All questions is cached in $opt_dir/'server_name'.cfg that future runs will use
  1523. limits found in previous runs. Remove this file if you want to find the
  1524. current limits for your version of the database server.
  1525.  
  1526. This program uses some table names while testing things. If you have any
  1527. tables with the name of 'crash_me' or 'crash_qxxxx' where 'x' is a number,
  1528. they will be deleted by this test!
  1529.  
  1530. $0 takes the following options:
  1531.  
  1532. --help or --Information
  1533.   Shows this help
  1534.  
  1535. --batch-mode
  1536.   Don\'t ask any questions, quit on errors.
  1537.  
  1538. --comment='some comment'
  1539.   Add this comment to the crash-me limit file
  1540.  
  1541. --database='database' (Default $opt_database)
  1542.   Create test tables in this database.
  1543.  
  1544. --dir='limits'
  1545.   Save crash-me output in this directory
  1546.  
  1547. --debug
  1548.   Lots of printing to help debugging if something goes wrong.
  1549.  
  1550. --fix-limit-file
  1551.   Reformat the crash-me limit file.  crash-me is not run!
  1552.  
  1553. --force
  1554.   Start test at once, without a warning screen and without questions.
  1555.   This is a option for the very brave.
  1556.   Use this in your cron scripts to test your database every night.
  1557.  
  1558. --log-all-queries
  1559.   Prints all queries that are executed. Mostly used for debugging crash-me.
  1560.  
  1561. --host='hostname' (Default $opt_host)
  1562.   Run tests on this host.
  1563.  
  1564. --password='password'
  1565.   Password for the current user.
  1566.  
  1567. --restart
  1568.   Save states during each limit tests. This will make it possible to continue
  1569.   by restarting with the same options if there is some bug in the DBI or
  1570.   DBD driver that caused $0 to die!
  1571.  
  1572. --server='server name'  (Default $opt_server)
  1573.   Run the test on the given server.
  1574.   Known servers names are: Empress, mSQL, MySQL, Pg, Solid and Oracle.
  1575.   For others $0 can\'t report the server version.
  1576.  
  1577. --user='user_name'
  1578.   User name to log into the SQL server.
  1579.  
  1580. --start-cmd='command to restart server'
  1581.   Automaticly restarts server with this command if the server dies.
  1582.  
  1583. --sleep='time in seconds' (Default $opt_sleep)
  1584.   Wait this long before restarting server.
  1585.  
  1586. EOF
  1587.   exit(0);
  1588. }
  1589.  
  1590.  
  1591. sub server_info
  1592. {
  1593.   my ($ok,$tmp);
  1594.   $ok=0;
  1595.   print "\nNOTE: You should be familiar with '$0 --help' before continuing!\n\n";
  1596.   if (lc($opt_server) eq "mysql")
  1597.   {
  1598.     $ok=1;
  1599.     print <<EOF;
  1600. This test should not crash MySQL if it was distributed together with the
  1601. running MySQL version.
  1602. If this is the case you can probably continue without having to worry about
  1603. destroying something.
  1604. EOF
  1605.   }
  1606.   elsif (lc($opt_server) eq "msql")
  1607.   {
  1608.     print <<EOF;
  1609. This test will take down mSQL repeatedly while finding limits.
  1610. To make this test easier, start mSQL in another terminal with something like:
  1611.  
  1612. while (true); do /usr/local/mSQL/bin/msql2d ; done
  1613.  
  1614. You should be sure that no one is doing anything important with mSQL and that
  1615. you have privileges to restart it!
  1616. It may take awhile to determinate the number of joinable tables, so prepare to
  1617. wait!
  1618. EOF
  1619.   }
  1620.   elsif (lc($opt_server) eq "solid")
  1621.   {
  1622.     print <<EOF;
  1623. This test will take down Solid server repeatedly while finding limits.
  1624. You should be sure that no one is doing anything important with Solid
  1625. and that you have privileges to restart it!
  1626.  
  1627. If you are running Solid without logging and/or backup YOU WILL LOSE!
  1628. Solid does not write data from the cache often enough. So if you continue
  1629. you may lose tables and data that you entered hours ago!
  1630.  
  1631. Solid will also take a lot of memory running this test. You will nead
  1632. at least 234M free!
  1633.  
  1634. When doing the connect test Solid server or the perl api will hang when
  1635. freeing connections. Kill this program and restart it to continue with the
  1636. test. You don\'t have to use --restart for this case.
  1637. EOF
  1638.     if (!$opt_restart)
  1639.     {
  1640.       print "\nWhen DBI/Solid dies you should run this program repeatedly\n";
  1641.       print "with --restart until all tests have completed\n";
  1642.     }
  1643.   }
  1644.   elsif (lc($opt_server) eq "pg")
  1645.   {
  1646.     print <<EOF;
  1647. This test will crash postgreSQL when calculating the number of joinable tables!
  1648. You should be sure that no one is doing anything important with postgreSQL
  1649. and that you have privileges to restart it!
  1650. EOF
  1651.   }
  1652.   else
  1653.   {
  1654.     print <<EOF;
  1655. This test may crash $opt_server repeatedly while finding limits!
  1656. You should be sure that no one is doing anything important with $opt_server
  1657. and that you have privileges to restart it!
  1658. EOF
  1659.   }
  1660.   print <<EOF;
  1661.  
  1662. You can always contact your database vendor and ask if the database server
  1663. is $0 safe.  As crash-me only uses legal SQL statements to test the
  1664. server, any reasonable server should be crash-me safe. Unfortunately this
  1665. isn\'t the case for all SQL servers.
  1666.  
  1667. We, the creators of this utility, are not responsible in any way if your
  1668. database server unexpectedly crashes while this program tries to find the
  1669. limitations of your server. By accepting the following question with 'yes',
  1670. you agree to the above!
  1671.  
  1672. EOF
  1673.  
  1674.   #
  1675.   # No default reply here so no one can blame us for starting the test
  1676.   # automaticly.
  1677.   #
  1678.   for (;;)
  1679.   {
  1680.     print "Start test (yes/no) ? ";
  1681.     $tmp=<STDIN>; chomp($tmp); $tmp=lc($tmp);
  1682.     last if ($tmp =~ /^yes$/i);
  1683.     exit 1 if ($tmp =~ /^n/i);
  1684.     print "\n";
  1685.   }
  1686. }
  1687.  
  1688. sub machine
  1689. {
  1690.   $name= `uname -s -r -m`;
  1691.   if ($?)
  1692.   {
  1693.     $name= `uname -s -m`;
  1694.   }
  1695.   if ($?)
  1696.   {
  1697.     $name= `uname -s`;
  1698.   }
  1699.   if ($?)
  1700.   {
  1701.     $name= `uname`;
  1702.   }
  1703.   if ($?)
  1704.   {
  1705.     $name="unknown";
  1706.   }
  1707.   chomp($name); $name =~ s/[\n\r]//g;
  1708.   return $name;
  1709. }
  1710.  
  1711.  
  1712. #
  1713. # Help functions that we need
  1714. #
  1715.  
  1716. sub safe_connect
  1717. {
  1718.   my ($object)=@_;
  1719.   my ($dbh,$tmp);
  1720.  
  1721.   for (;;)
  1722.   {
  1723.     if (($dbh=DBI->connect($server->{'data_source'},$opt_user,$opt_password,
  1724.                { PrintError => 0})))
  1725.     {
  1726.       $dbh->{LongReadLen}= 16000000; # Set max retrieval buffer
  1727.       return $dbh;
  1728.     }
  1729.     print "Error: $DBI::errstr;  $server->{'data_source'}  - '$opt_user' - '$opt_password'\n";
  1730.     print "I got the above error when connecting to $opt_server\n";
  1731.     if (defined($object) && defined($object->{'limit'}))
  1732.     {
  1733.       print "This check was done with limit: $object->{'limit'}.\nNext check will be done with a smaller limit!\n";
  1734.       $object=undef();
  1735.     }
  1736.     save_config_data('crash_me_safe','no',"crash me safe");
  1737.     if ($opt_db_start_cmd)
  1738.     {
  1739.       print "Restarting the db server with:\n'$opt_db_start_cmd'\n";
  1740.       system("$opt_db_start_cmd");
  1741.       print "Waiting $opt_sleep seconds so the server can initialize\n";
  1742.       sleep $opt_sleep;
  1743.     }
  1744.     else
  1745.     {
  1746.       exit(1) if ($opt_batch_mode);
  1747.       print "Can you check/restart it so I can continue testing?\n";
  1748.       for (;;)
  1749.       {
  1750.     print "Continue test (yes/no) ? [yes] ";
  1751.     $tmp=<STDIN>; chomp($tmp); $tmp=lc($tmp);
  1752.     $tmp = "yes" if ($tmp eq "");
  1753.     last if (index("yes",$tmp) >= 0);
  1754.     exit 1 if (index("no",$tmp) >= 0);
  1755.     print "\n";
  1756.       }
  1757.     }
  1758.   }
  1759. }
  1760.  
  1761. #
  1762. # Check if the server is upp and running. If not, ask the user to restart it
  1763. #
  1764.  
  1765. sub check_connect
  1766. {
  1767.   my ($object)=@_;
  1768.   print "Checking connection\n" if ($opt_log_all_queries);
  1769.   return if (defined($check_connect) && defined($dbh->do($check_connect)));
  1770.   $dbh->disconnect;
  1771.   print "\nreconnecting\n" if ($opt_debug);
  1772.   $reconnect_count++;
  1773.   $dbh=safe_connect($object);
  1774. }
  1775.  
  1776. #
  1777. # print query if debugging
  1778. #
  1779. sub print_query
  1780. {
  1781.   my ($query)=@_;
  1782.   $last_error=$DBI::errstr;
  1783.   if ($opt_debug)
  1784.   {
  1785.     if (length($query) > 130)
  1786.     {
  1787.       $query=substr($query,0,120) . "...(" . (length($query)-120) . ")";
  1788.     }
  1789.     printf "\nGot error from query: '%s'\n%s\n",$query,$DBI::errstr;
  1790.   }
  1791. }
  1792.  
  1793. #
  1794. # Do one or many queries. Return 1 if all was ok
  1795. #
  1796.  
  1797. sub safe_query
  1798. {
  1799.   my($queries)=@_;
  1800.   my($query,$ok,$retry,@tmp);
  1801.   $ok=1;
  1802.   if (ref($queries) ne "ARRAY")
  1803.   {
  1804.     push(@tmp,$queries);
  1805.     $queries= \@tmp;
  1806.   }
  1807.   foreach $query (@$queries)
  1808.   {
  1809.     printf "query1: %-80.80s ...(%d)\n",$query,length($query)  if ($opt_log_all_queries);
  1810.     if (length($query) > $query_size)
  1811.     {
  1812.       $ok=0;
  1813.       next;
  1814.     }
  1815.     for ($retry=0; $retry < $retry_limit ; $retry++)
  1816.     {
  1817.       if (!$dbh->do($query))
  1818.       {
  1819.     print_query($query);
  1820.     $retry=100 if (!$server->abort_if_fatal_error());
  1821.     # Force a reconnect because of Access drop table bug!
  1822.     if ($retry == $retry_limit-2)
  1823.     {
  1824.       print "Forcing discoennect to retry query\n" if ($opt_debug);
  1825.       $dbh->disconnect;
  1826.     }
  1827.     check_connect();        # Check that server is still up
  1828.     $ok=0;                  # Didn't work. Continue with cleanup
  1829.       }
  1830.       else
  1831.       {
  1832.     last;
  1833.       }
  1834.     }
  1835.   }
  1836.   return $ok;
  1837. }
  1838.  
  1839.  
  1840. #
  1841. # Do a query on a query package object.
  1842. #
  1843.  
  1844. sub limit_query
  1845. {
  1846.   my($object,$limit)=@_;
  1847.   my ($query,$result,$retry,$sth);
  1848.  
  1849.   $query=$object->query($limit);
  1850.   $result=safe_query($query);
  1851.   if (!$result)
  1852.   {
  1853.     $object->cleanup();
  1854.     return 0;
  1855.   }
  1856.   if (defined($query=$object->check_query()))
  1857.   {
  1858.     for ($retry=0 ; $retry < $retry_limit ; $retry++)
  1859.     {
  1860.       printf "query2: %-80.80s\n",$query if ($opt_log_all_queries);
  1861.       if (($sth= $dbh->prepare($query)))
  1862.       {
  1863.     if ($sth->execute)
  1864.     {
  1865.       $result= $object->check($sth);
  1866.       $sth->finish;
  1867.       $object->cleanup();
  1868.       return $result;
  1869.     }
  1870.     print_query($query);
  1871.     $sth->finish;
  1872.       }
  1873.       else
  1874.       {
  1875.     print_query($query);
  1876.       }
  1877.       $retry=100 if (!$server->abort_if_fatal_error()); # No need to continue
  1878.       if ($retry == $retry_limit-2)
  1879.       {
  1880.     print "Forcing discoennect to retry query\n" if ($opt_debug);
  1881.     $dbh->disconnect;
  1882.       }
  1883.       check_connect($object);   # Check that server is still up
  1884.     }
  1885.     $result=0;                  # Query failed
  1886.   }
  1887.   $object->cleanup();
  1888.   return $result;               # Server couldn't handle the query
  1889. }
  1890.  
  1891.  
  1892. sub report
  1893. {
  1894.   my ($prompt,$limit,@queries)=@_;
  1895.   print "$prompt: ";
  1896.   if (!defined($limits{$limit}))
  1897.   {
  1898.     save_config_data($limit,safe_query(\@queries) ? "yes" : "no",$prompt);
  1899.   }
  1900.   print "$limits{$limit}\n";
  1901.   return $limits{$limit} ne "no";
  1902. }
  1903.  
  1904. sub report_fail
  1905. {
  1906.   my ($prompt,$limit,@queries)=@_;
  1907.   print "$prompt: ";
  1908.   if (!defined($limits{$limit}))
  1909.   {
  1910.     save_config_data($limit,safe_query(\@queries) ? "no" : "yes",$prompt);
  1911.   }
  1912.   print "$limits{$limit}\n";
  1913.   return $limits{$limit} ne "no";
  1914. }
  1915.  
  1916.  
  1917. # Return true if one of the queries is ok
  1918.  
  1919. sub report_one
  1920. {
  1921.   my ($prompt,$limit,$queries)=@_;
  1922.   my ($query,$res,$result);
  1923.   print "$prompt: ";
  1924.   if (!defined($limits{$limit}))
  1925.   {
  1926.     $result="no";
  1927.     foreach $query (@$queries)
  1928.     {
  1929.       if (safe_query($query->[0]))
  1930.       {
  1931.     $result= $query->[1];
  1932.     last;
  1933.       }
  1934.     }
  1935.     save_config_data($limit,$result,$prompt);
  1936.   }
  1937.   print "$limits{$limit}\n";
  1938.   return $limits{$limit} ne "no";
  1939. }
  1940.  
  1941.  
  1942. # Execute query and save result as limit value.
  1943.  
  1944. sub report_result
  1945. {
  1946.   my ($prompt,$limit,$query)=@_;
  1947.   my($error);
  1948.   print "$prompt: ";
  1949.   if (!defined($limits{$limit}))
  1950.   {
  1951.     $error=safe_query_result($query,"1",2);
  1952.     save_config_data($limit,$error ? "not supported" : $last_result,$prompt);
  1953.   }
  1954.   print "$limits{$limit}\n";
  1955.   return $limits{$limit} ne "no";
  1956. }
  1957.  
  1958. sub report_trans
  1959. {
  1960.   my ($prompt,$limit,$queries,$check,$clear)=@_;
  1961.   print "$prompt: ";
  1962.   if (!defined($limits{$limit}))
  1963.   {
  1964.     eval {undef($dbh->{AutoCommit})};
  1965.     if (!$@)
  1966.     {
  1967.       if (safe_query(\@$queries))
  1968.       {
  1969.       $rc = $dbh->rollback;
  1970.       if ($rc) {
  1971.         $dbh->{AutoCommit} = 1;
  1972.         if (safe_query_result($check,"","")) {
  1973.           save_config_data($limit,"yes",$prompt);
  1974.         }
  1975.       } else {
  1976.         $dbh->{AutoCommit} = 1;
  1977.         safe_query($clear);
  1978.         save_config_data($limit,"error",$prompt);
  1979.       }
  1980.       } else {
  1981.         save_config_data($limit,"error",$prompt);
  1982.       }
  1983.       $dbh->{AutoCommit} = 1;
  1984.     }
  1985.     else
  1986.     {
  1987.       save_config_data($limit,"no",$prompt);
  1988.     }
  1989.   }
  1990.   print "$limits{$limit}\n";
  1991.   return $limits{$limit} ne "no";
  1992. }
  1993.  
  1994.  
  1995. sub check_and_report
  1996. {
  1997.   my ($prompt,$limit,$pre,$query,$post,$answer,$string_type,$skip_prompt,
  1998.       $function)=@_;
  1999.   my ($tmp);
  2000.   $function=0 if (!defined($function));
  2001.  
  2002.   print "$prompt: " if (!defined($skip_prompt));
  2003.   if (!defined($limits{$limit}))
  2004.   {
  2005.     $tmp=1-safe_query(\@$pre);
  2006.     $tmp=safe_query_result($query,$answer,$string_type) if (!$tmp);
  2007.     safe_query(\@$post);
  2008.     if ($function == 0 ||
  2009.     $tmp != 0 && $function == 1 ||
  2010.     $tmp == 0 && $function== 2)
  2011.     {
  2012.       save_config_data($limit, $tmp == 0 ? "yes" : $tmp == 1 ? "no" : "error",
  2013.                $prompt);
  2014.       print "$limits{$limit}\n";
  2015.       return $function == 0 ? $limits{$limit} eq "yes" : 0;
  2016.     }
  2017.     return 1;            # more things to check
  2018.   }
  2019.   print "$limits{$limit}\n";
  2020.   return 0 if (defined($function));
  2021.   return $limits{$limit} eq "yes";
  2022. }
  2023.  
  2024.  
  2025. # returns 0 if ok, 1 if error, -1 if wrong answer
  2026. # Sets $last_result to value of query
  2027.  
  2028. sub safe_query_result
  2029. {
  2030.   my ($query,$answer,$result_type)=@_;
  2031.   my ($sth,$row,$result,$retry);
  2032.   undef($last_result);
  2033.  
  2034.   printf "\nquery3: %-80.80s\n",$query  if ($opt_log_all_queries);
  2035.   for ($retry=0; $retry < $retry_limit ; $retry++)
  2036.   {
  2037.     if (!($sth=$dbh->prepare($query)))
  2038.     {
  2039.       print_query($query);
  2040.       if ($server->abort_if_fatal_error())
  2041.       {
  2042.     check_connect();                # Check that server is still up
  2043.     next;                           # Retry again
  2044.       }
  2045.       check_connect();              # Check that server is still up
  2046.       return 1;
  2047.     }
  2048.     if (!$sth->execute)
  2049.     {
  2050.       print_query($query);
  2051.       if ($server->abort_if_fatal_error())
  2052.       {
  2053.     check_connect();                # Check that server is still up
  2054.     next;                           # Retry again
  2055.       }
  2056.       check_connect();              # Check that server is still up
  2057.       return 1;
  2058.     }
  2059.     if (!($row=$sth->fetchrow_arrayref))
  2060.     {
  2061.       print "\nquery: $query didn't return any result\n" if ($opt_debug);
  2062.       return 1;
  2063.     }
  2064.     $result=0;                      # Ok
  2065.     $last_result= $row->[0];        # Save for report_result;
  2066.     if ($result_type == 0)        # Compare numbers
  2067.     {
  2068.       if ($row->[0] != $answer && (abs($row->[0]- $answer)/
  2069.                    (abs($row->[0]) + abs($answer))) > 0.01)
  2070.       {
  2071.     $result=-1;
  2072.       }
  2073.     }
  2074.     elsif ($result_type == 1)   # Compare where end space may differ
  2075.     {
  2076.       $row->[0] =~ s/\s+$//;
  2077.       $result=-1 if ($row->[0] ne $answer);
  2078.     }
  2079.     elsif ($result_type == 3)   # This should be a exact match
  2080.     {
  2081.       $result= -1 if ($row->[0] ne $answer);
  2082.     }
  2083.     elsif ($result_type == 4)   # If results should be NULL
  2084.     {
  2085.       $result= -1 if (defined($row->[0]));
  2086.     }
  2087.     elsif ($result_type == 5)   # Result should have given prefix
  2088.     {
  2089.       $result= -1 if (length($row->[0]) < length($answer) &&
  2090.               substring($row->[0],1,length($answer)) ne $answer);
  2091.     }
  2092.     elsif ($result_type == 6)    # Exact match but ignore errors
  2093.     {
  2094.       $result= 1 if ($row->[0] ne $answer);
  2095.     }
  2096.     $sth->finish;
  2097.   }
  2098.   print "\nquery: '$query' returned '$row->[0]' instead of '$answer'\n"
  2099.     if ($opt_debug && $result);
  2100.   return $result;
  2101. }
  2102.  
  2103. #
  2104. # Find limit using binary search.  This is a weighed binary search that
  2105. # will prefere lower limits to get the server to crash as few times as possible
  2106. #
  2107.  
  2108. sub find_limit()
  2109. {
  2110.   my ($prompt,$limit,$query)=@_;
  2111.   my ($first,$end,$i,$tmp);
  2112.   print "$prompt: ";
  2113.   if (defined($end=$limits{$limit}))
  2114.   {
  2115.     print "$end (cache)\n";
  2116.     return $end;
  2117.   }
  2118.   if (defined($query->{'init'}) && !defined($end=$limits{'restart'}{'tohigh'}))
  2119.   {
  2120.     if (!safe_query($query->{'init'}))
  2121.     {
  2122.       $query->cleanup();
  2123.       return "error";
  2124.     }
  2125.   }
  2126.  
  2127.   if (!limit_query($query,1))           # This must work
  2128.   {
  2129.     print "\nMaybe fatal error: Can't check '$prompt' for limit=1\nerror: $last_error\n";
  2130.     return "error";
  2131.   }
  2132.  
  2133.   $first=0;
  2134.   $first=$limits{'restart'}{'low'} if ($limits{'restart'}{'low'});
  2135.  
  2136.   if (defined($end=$limits{'restart'}{'tohigh'}))
  2137.   {
  2138.     $end--;
  2139.     print "\nRestarting this with low limit: $first and high limit: $end\n";
  2140.     delete $limits{'restart'};
  2141.     $i=$first+int(($end-$first+4)/5);           # Prefere lower on errors
  2142.   }
  2143.   else
  2144.   {
  2145.     $end= $query->max_limit();
  2146.     $i=int(($end+$first)/2);
  2147.   }
  2148.   while ($first < $end)
  2149.   {
  2150.     print "." if ($opt_debug);
  2151.     save_config_data("restart",$i,"") if ($opt_restart);
  2152.     if (limit_query($query,$i))
  2153.     {
  2154.       $first=$i;
  2155. #      $i=$first+int(($end-$first+2)/3);
  2156.       $i=$first+int(($end-$first+1)/2); # to be a bit faster to go up
  2157.     }
  2158.     else
  2159.     {
  2160.       $end=$i-1;
  2161.       $i=$first+int(($end-$first+4)/5); # Prefere lower on errors
  2162.     }
  2163.   }
  2164.   $end+=$query->{'offset'} if ($end && defined($query->{'offset'}));
  2165.   if ($end >= $query->{'max_limit'} &&
  2166.       substr($query->{'max_limit'},0,1) eq '+')
  2167.   {
  2168.     $end= $query->{'max_limit'};
  2169.   }
  2170.   print "$end\n";
  2171.   save_config_data($limit,$end,$prompt);
  2172.   delete $limits{'restart'};
  2173.   return $end;
  2174. }
  2175.  
  2176. #
  2177. # Check that the query works!
  2178. #
  2179.  
  2180. sub assert
  2181. {
  2182.   my($query)=@_;
  2183.  
  2184.   if (!safe_query($query))
  2185.   {
  2186.     $query=join("; ",@$query) if (ref($query) eq "ARRAY");
  2187.     print "\nFatal error:\nquery: '$query'\nerror: $DBI::errstr\n";
  2188.     exit 1;
  2189.   }
  2190. }
  2191.  
  2192.  
  2193. sub read_config_data
  2194. {
  2195.   my ($key,$limit,$prompt);
  2196.   if (-e "$pwd/$opt_dir/$opt_server.cfg")
  2197.   {
  2198.     open(CONFIG_FILE,"+<$pwd/$opt_dir/$opt_server.cfg") ||
  2199.       die "Can't open configure file $pwd/$opt_dir/$opt_server.cfg\n";
  2200.     print "Reading old values from cache: $opt_dir/$opt_server.cfg\n";
  2201.   }
  2202.   else
  2203.   {
  2204.     open(CONFIG_FILE,"+>>$pwd/$opt_dir/$opt_server.cfg") ||
  2205.       die "Can't create configure file $pwd/$opt_dir/$opt_server.cfg: $!\n";
  2206.   }
  2207.   select CONFIG_FILE;
  2208.   $|=1;
  2209.   select STDOUT;
  2210.   while (<CONFIG_FILE>)
  2211.   {
  2212.     chomp;
  2213.     if (/^(\S+)=([^\#]*[^\#\s])\s*(\# .*)*$/)
  2214.     {
  2215.       $key=$1; $limit=$2 ; $prompt=$3;
  2216.       if (!$opt_quick || $limit =~ /\d/ || $key =~ /crash_me/)
  2217.       {
  2218.     if ($key !~ /restart/i)
  2219.     {
  2220.       $limits{$key}=$limit;
  2221.       $prompts{$key}=length($prompt) ? substr($prompt,2) : "";
  2222.       delete $limits{'restart'};
  2223.     }
  2224.     else
  2225.     {
  2226.       $limit_changed=1;
  2227.       if ($limit > $limits{'restart'}{'tohigh'})
  2228.       {
  2229.         $limits{'restart'}{'low'} = $limits{'restart'}{'tohigh'};
  2230.       }
  2231.       $limits{'restart'}{'tohigh'} = $limit;
  2232.     }
  2233.       }
  2234.     }
  2235.     elsif (!/^\s*$/ && !/^\#/)
  2236.     {
  2237.       die "Wrong config row: $_\n";
  2238.     }
  2239.   }
  2240. }
  2241.  
  2242.  
  2243. sub save_config_data
  2244. {
  2245.   my ($key,$limit,$prompt)=@_;
  2246.   $prompts{$key}=$prompt;
  2247.   return if (defined($limits{$key}) && $limits{$key} eq $limit);
  2248.   if (!defined($limit) || $limit eq "")
  2249.   {
  2250.     die "Undefined limit for $key\n";
  2251.   }
  2252.   print CONFIG_FILE "$key=$limit\t# $prompt\n";
  2253.   $limits{$key}=$limit;
  2254.   $limit_changed=1;
  2255.   if (($opt_restart && $limits{'operating_system'} =~ /windows/i) ||
  2256.                ($limits{'operating_system'} =~ /NT/))
  2257.   {
  2258.     # If perl crashes in windows, everything is lost (Wonder why? :)
  2259.     close CONFIG_FILE;
  2260.     open(CONFIG_FILE,"+>>$pwd/$opt_dir/$opt_server.cfg") ||
  2261.       die "Can't reopen configure file $pwd/$opt_dir/$opt_server.cfg: $!\n";
  2262.   }
  2263. }
  2264.  
  2265.  
  2266. sub save_all_config_data
  2267. {
  2268.   my ($key,$tmp);
  2269.   close CONFIG_FILE;
  2270.   return if (!$limit_changed);
  2271.   open(CONFIG_FILE,">$pwd/$opt_dir/$opt_server.cfg") ||
  2272.     die "Can't create configure file $pwd/$opt_dir/$opt_server.cfg: $!\n";
  2273.   select CONFIG_FILE;
  2274.   $|=1;
  2275.   select STDOUT;
  2276.   delete $limits{'restart'};
  2277.  
  2278.   print CONFIG_FILE "#This file is automaticly generated by crash-me $version\n\n";
  2279.   foreach $key (sort keys %limits)
  2280.   {
  2281.     $tmp="$key=$limits{$key}";
  2282.     print CONFIG_FILE $tmp . ("\t" x (int((32-min(length($tmp),32)+7)/8)+1)) .
  2283.       "# $prompts{$key}\n";
  2284.   }
  2285.   close CONFIG_FILE;
  2286. }
  2287.  
  2288.  
  2289. sub check_repeat
  2290. {
  2291.   my ($sth,$limit)=@_;
  2292.   my ($row);
  2293.  
  2294.   return 0 if (!($row=$sth->fetchrow_arrayref));
  2295.   return (defined($row->[0]) && ('a' x $limit) eq $row->[0]) ? 1 : 0;
  2296. }
  2297.  
  2298.  
  2299. sub min
  2300. {
  2301.   my($min)=$_[0];
  2302.   my($i);
  2303.   for ($i=1 ; $i <= $#_; $i++)
  2304.   {
  2305.     $min=$_[$i] if ($min > $_[$i]);
  2306.   }
  2307.   return $min;
  2308. }
  2309.  
  2310. sub sql_concat
  2311. {
  2312.   my ($a,$b)= @_;
  2313.   return "$a || $b" if ($limits{'func_sql_concat_as_||'} eq 'yes');
  2314.   return "concat($a,$b)" if ($limits{'func_odbc_concat'} eq 'yes');
  2315.   return "$a + $b" if ($limits{'func_extra_concat_as_+'} eq 'yes');
  2316.   return undef;
  2317. }
  2318.  
  2319. #
  2320. # Returns a list of statements to create a table in a portable manner
  2321. # but still utilizing features in the databases.
  2322. #
  2323.  
  2324. sub create_table
  2325. {
  2326.   my($table_name,$fields,$index) = @_;
  2327.   my($query,$nr,$parts,@queries,@index);
  2328.  
  2329.   $query="create table $table_name (";
  2330.   $nr=0;
  2331.   foreach $field (@$fields)
  2332.   {
  2333.     $query.= $field . ',';
  2334.   }
  2335.   foreach $index (@$index)
  2336.   {
  2337.     $index =~ /\(([^\(]*)\)$/i;
  2338.     $parts=$1;
  2339.     if ($index =~ /^primary key/)
  2340.     {
  2341.       if ($limits{'primary_key_in_create'} eq 'yes')
  2342.       {
  2343.     $query.= $index . ',';
  2344.       }
  2345.       else
  2346.       {
  2347.     push(@queries,
  2348.          "create unique index ${table_name}_prim on $table_name ($parts)");
  2349.       }
  2350.     }
  2351.     elsif ($index =~ /^unique/)
  2352.     {
  2353.       if ($limits{'unique_in_create'} eq 'yes')
  2354.       {
  2355.     $query.= "unique ($parts),";
  2356.       }
  2357.       else
  2358.       {
  2359.     $nr++;
  2360.     push(@queries,
  2361.          "create unique index ${table_name}_$nr on $table_name ($parts)");
  2362.  
  2363.       }
  2364.     }
  2365.     else
  2366.     {
  2367.       if ($limits{'index_in_create'} eq 'yes')
  2368.       {
  2369.     $query.= "index ($parts),";
  2370.       }
  2371.       else
  2372.       {
  2373.     $nr++;
  2374.     push(@queries,
  2375.          "create index ${table_name}_$nr on $table_name ($1)");
  2376.       }
  2377.     }
  2378.   }
  2379.   chop($query);
  2380.   $query.= ')';
  2381.   unshift(@queries,$query);
  2382.   return @queries;
  2383. }
  2384.  
  2385.  
  2386. #
  2387. # This is used by some query packages to change:
  2388. # %d -> limit
  2389. # %s -> 'a' x limit
  2390. # %v -> "1,1,1,1,1" where there are 'limit' number of ones
  2391. # %f -> q1,q2,q3....
  2392. # %F -> q1 integer,q2 integer,q3 integer....
  2393.  
  2394. sub fix_query
  2395. {
  2396.   my ($query,$limit)=@_;
  2397.   my ($repeat,$i);
  2398.  
  2399.   return $query if !(defined($query));
  2400.   $query =~ s/%d/$limit/g;
  2401.   if ($query =~ /%s/)
  2402.   {
  2403.     $repeat= 'a' x $limit;
  2404.     $query =~ s/%s/$repeat/g;
  2405.   }
  2406.   if ($query =~ /%v/)
  2407.   {
  2408.     $repeat= '1,' x $limit;
  2409.     chop($repeat);
  2410.     $query =~ s/%v/$repeat/g;
  2411.   }
  2412.   if ($query =~ /%f/)
  2413.   {
  2414.     $repeat="";
  2415.     for ($i=1 ; $i <= $limit ; $i++)
  2416.     {
  2417.       $repeat.="q$i,";
  2418.     }
  2419.     chop($repeat);
  2420.     $query =~ s/%f/$repeat/g;
  2421.   }
  2422.   if ($query =~ /%F/)
  2423.   {
  2424.     $repeat="";
  2425.     for ($i=1 ; $i <= $limit ; $i++)
  2426.     {
  2427.       $repeat.="q$i integer,";
  2428.     }
  2429.     chop($repeat);
  2430.     $query =~ s/%F/$repeat/g;
  2431.   }
  2432.   return $query;
  2433. }
  2434.  
  2435.  
  2436. #
  2437. # Different query packages
  2438. #
  2439.  
  2440. package query_repeat;
  2441.  
  2442. sub new
  2443. {
  2444.   my ($type,$init,$query,$add1,$add_mid,$add,$add_end,$end_query,$cleanup,
  2445.       $max_limit, $check, $offset)=@_;
  2446.   my $self={};
  2447.   if (defined($init) && $#$init != -1)
  2448.   {
  2449.     $self->{'init'}=$init;
  2450.   }
  2451.   $self->{'query'}=$query;
  2452.   $self->{'add1'}=$add1;
  2453.   $self->{'add_mid'}=$add_mid;
  2454.   $self->{'add'}=$add;
  2455.   $self->{'add_end'}=$add_end;
  2456.   $self->{'end_query'}=$end_query;
  2457.   $self->{'cleanup'}=$cleanup;
  2458.   $self->{'max_limit'}=(defined($max_limit) ? $max_limit : $main::query_size);
  2459.   $self->{'check'}=$check;
  2460.   $self->{'offset'}=$offset;
  2461.   $self->{'printf'}= ($add =~ /%d/);
  2462.   bless $self;
  2463. }
  2464.  
  2465. sub query
  2466. {
  2467.   my ($self,$limit)=@_;
  2468.   if (!$self->{'printf'})
  2469.   {
  2470.     return $self->{'query'} . ($self->{'add'} x $limit) .
  2471.       ($self->{'add_end'} x $limit) . $self->{'end_query'};
  2472.   }
  2473.   my ($tmp,$tmp2,$tmp3,$i);
  2474.   $tmp=$self->{'query'};
  2475.   if ($self->{'add1'})
  2476.   {
  2477.     for ($i=0; $i < $limit ; $i++)
  2478.     {
  2479.       $tmp3 = $self->{'add1'};
  2480.       $tmp3 =~ s/%d/$i/g;
  2481.       $tmp  .= $tmp3;
  2482.     }
  2483.   }
  2484.   $tmp .= " ".$self->{'add_mid'};
  2485.   if ($self->{'add'})
  2486.   {
  2487.     for ($i=0; $i < $limit ; $i++)
  2488.     {
  2489.       $tmp2 = $self->{'add'};
  2490.       $tmp2 =~ s/%d/$i/g;
  2491.       $tmp  .= $tmp2;
  2492.     }
  2493.   }
  2494.   return ($tmp .
  2495.       ($self->{'add_end'} x $limit) . $self->{'end_query'});
  2496. }
  2497.  
  2498. sub max_limit
  2499. {
  2500.   my ($self)=@_;
  2501.   my $tmp;
  2502.   $tmp=int(($main::limits{"query_size"}-length($self->{'query'})
  2503.         -length($self->{'add_mid'})-length($self->{'end_query'}))/
  2504.        (length($self->{'add1'})+
  2505.        length($self->{'add'})+length($self->{'add_end'})));
  2506.   return main::min($self->{'max_limit'},$tmp);
  2507. }
  2508.  
  2509.  
  2510. sub cleanup
  2511. {
  2512.   my ($self)=@_;
  2513.   my($tmp,$statement);
  2514.   $tmp=$self->{'cleanup'};
  2515.   foreach $statement (@$tmp)
  2516.   {
  2517.     main::safe_query($statement) if (defined($statement) && length($statement));
  2518.   }
  2519. }
  2520.  
  2521. sub check
  2522. {
  2523.   my ($self,$sth)=@_;
  2524.   my $check=$self->{'check'};
  2525.   return &$check($sth,$self->{'limit'}) if (defined($check));
  2526.   return 1;
  2527. }
  2528.  
  2529. sub check_query
  2530. {
  2531.   return undef;
  2532. }
  2533.  
  2534.  
  2535. package query_num;
  2536.  
  2537. sub new
  2538. {
  2539.   my ($type,$query,$end_query,$cleanup,$max_limit,$check)=@_;
  2540.   my $self={};
  2541.   $self->{'query'}=$query;
  2542.   $self->{'end_query'}=$end_query;
  2543.   $self->{'cleanup'}=$cleanup;
  2544.   $self->{'max_limit'}=$max_limit;
  2545.   $self->{'check'}=$check;
  2546.   bless $self;
  2547. }
  2548.  
  2549.  
  2550. sub query
  2551. {
  2552.   my ($self,$i)=@_;
  2553.   $self->{'limit'}=$i;
  2554.   return "$self->{'query'}$i$self->{'end_query'}";
  2555. }
  2556.  
  2557. sub max_limit
  2558. {
  2559.   my ($self)=@_;
  2560.   return $self->{'max_limit'};
  2561. }
  2562.  
  2563. sub cleanup
  2564. {
  2565.   my ($self)=@_;
  2566.   my($statement);
  2567.   foreach $statement ($self->{'$cleanup'})
  2568.   {
  2569.     main::safe_query($statement) if (defined($statement) && length($statement));
  2570.   }
  2571. }
  2572.  
  2573.  
  2574. sub check
  2575. {
  2576.   my ($self,$sth)=@_;
  2577.   my $check=$self->{'check'};
  2578.   return &$check($sth,$self->{'limit'}) if (defined($check));
  2579.   return 1;
  2580. }
  2581.  
  2582. sub check_query
  2583. {
  2584.   return undef;
  2585. }
  2586.  
  2587. #
  2588. # This package is used when testing CREATE TABLE!
  2589. #
  2590.  
  2591. package query_table;
  2592.  
  2593. sub new
  2594. {
  2595.   my ($type,$query, $add, $end_query, $extra_init, $safe_query, $check,
  2596.       $cleanup, $max_limit, $offset)=@_;
  2597.   my $self={};
  2598.   $self->{'query'}=$query;
  2599.   $self->{'add'}=$add;
  2600.   $self->{'end_query'}=$end_query;
  2601.   $self->{'extra_init'}=$extra_init;
  2602.   $self->{'safe_query'}=$safe_query;
  2603.   $self->{'check'}=$check;
  2604.   $self->{'cleanup'}=$cleanup;
  2605.   $self->{'max_limit'}=$max_limit;
  2606.   $self->{'offset'}=$offset;
  2607.   bless $self;
  2608. }
  2609.  
  2610.  
  2611. sub query
  2612. {
  2613.   my ($self,$limit)=@_;
  2614.   $self->{'limit'}=$limit;
  2615.   $self->cleanup();     # Drop table before create
  2616.  
  2617.   my ($tmp,$tmp2,$i,$query,@res);
  2618.   $tmp =$self->{'query'};
  2619.   $tmp =~ s/%d/$limit/g;
  2620.   for ($i=1; $i <= $limit ; $i++)
  2621.   {
  2622.     $tmp2 = $self->{'add'};
  2623.     $tmp2 =~ s/%d/$i/g;
  2624.     $tmp  .= $tmp2;
  2625.   }
  2626.   push(@res,$tmp . $self->{'end_query'});
  2627.   $tmp=$self->{'extra_init'};
  2628.   foreach $query (@$tmp)
  2629.   {
  2630.     push(@res,main::fix_query($query,$limit));
  2631.   }
  2632.   return \@res;
  2633. }
  2634.  
  2635.  
  2636. sub max_limit
  2637. {
  2638.   my ($self)=@_;
  2639.   return $self->{'max_limit'};
  2640. }
  2641.  
  2642.  
  2643. sub check_query
  2644. {
  2645.   my ($self)=@_;
  2646.   return main::fix_query($self->{'safe_query'},$self->{'limit'});
  2647. }
  2648.  
  2649. sub check
  2650. {
  2651.   my ($self,$sth)=@_;
  2652.   my $check=$self->{'check'};
  2653.   return 0 if (!($row=$sth->fetchrow_arrayref));
  2654.   if (defined($check))
  2655.   {
  2656.     return (defined($row->[0]) &&
  2657.         $row->[0] eq main::fix_query($check,$self->{'limit'})) ? 1 : 0;
  2658.   }
  2659.   return 1;
  2660. }
  2661.  
  2662.  
  2663. # Remove table before and after create table query
  2664.  
  2665. sub cleanup()
  2666. {
  2667.   my ($self)=@_;
  2668.   main::safe_query(main::fix_query($self->{'cleanup'},$self->{'limit'}));
  2669. }
  2670.  
  2671. #
  2672. # Package to do many queries with %d, and %s substitution
  2673. #
  2674.  
  2675. package query_many;
  2676.  
  2677. sub new
  2678. {
  2679.   my ($type,$query,$safe_query,$check_result,$cleanup,$max_limit,$offset,
  2680.       $safe_cleanup)=@_;
  2681.   my $self={};
  2682.   $self->{'query'}=$query;
  2683.   $self->{'safe_query'}=$safe_query;
  2684.   $self->{'check'}=$check_result;
  2685.   $self->{'cleanup'}=$cleanup;
  2686.   $self->{'max_limit'}=$max_limit;
  2687.   $self->{'offset'}=$offset;
  2688.   $self->{'safe_cleanup'}=$safe_cleanup;
  2689.   bless $self;
  2690. }
  2691.  
  2692.  
  2693. sub query
  2694. {
  2695.   my ($self,$limit)=@_;
  2696.   my ($queries,$query,@res);
  2697.   $self->{'limit'}=$limit;
  2698.   $self->cleanup() if (defined($self->{'safe_cleanup'}));
  2699.   $queries=$self->{'query'};
  2700.   foreach $query (@$queries)
  2701.   {
  2702.     push(@res,main::fix_query($query,$limit));
  2703.   }
  2704.   return \@res;
  2705. }
  2706.  
  2707. sub check_query
  2708. {
  2709.   my ($self)=@_;
  2710.   return main::fix_query($self->{'safe_query'},$self->{'limit'});
  2711. }
  2712.  
  2713. sub cleanup
  2714. {
  2715.   my ($self)=@_;
  2716.   my($tmp,$statement);
  2717.   return if (!defined($self->{'cleanup'}));
  2718.   $tmp=$self->{'cleanup'};
  2719.   foreach $statement (@$tmp)
  2720.   {
  2721.     if (defined($statement) && length($statement))
  2722.     {
  2723.       main::safe_query(main::fix_query($statement,$self->{'limit'}));
  2724.     }
  2725.   }
  2726. }
  2727.  
  2728.  
  2729. sub check
  2730. {
  2731.   my ($self,$sth)=@_;
  2732.   my ($check,$row);
  2733.   return 0 if (!($row=$sth->fetchrow_arrayref));
  2734.   $check=$self->{'check'};
  2735.   if (defined($check))
  2736.   {
  2737.     return (defined($row->[0]) &&
  2738.         $row->[0] eq main::fix_query($check,$self->{'limit'})) ? 1 : 0;
  2739.   }
  2740.   return 1;
  2741. }
  2742.  
  2743. sub max_limit
  2744. {
  2745.   my ($self)=@_;
  2746.   return $self->{'max_limit'};
  2747. }
  2748.  
  2749. #
  2750. # Used to find max supported row length
  2751. #
  2752.  
  2753. package query_row_length;
  2754.  
  2755. sub new
  2756. {
  2757.   my ($type,$create,$null,$drop,$max_limit)=@_;
  2758.   my $self={};
  2759.   $self->{'table_name'}=$create;
  2760.   $self->{'null'}=$null;
  2761.   $self->{'cleanup'}=$drop;
  2762.   $self->{'max_limit'}=$max_limit;
  2763.   bless $self;
  2764. }
  2765.  
  2766.  
  2767. sub query
  2768. {
  2769.   my ($self,$limit)=@_;
  2770.   my ($res,$values,$size,$length,$i);
  2771.   $self->{'limit'}=$limit;
  2772.  
  2773.   $res="";
  2774.   $size=main::min($main::limits{'max_char_size'},255);
  2775.   for ($length=$i=0; $length + $size <= $limit ; $length+=$size, $i++)
  2776.   {
  2777.     $res.= "q$i char($size) $self->{'null'},";
  2778.     $values.="'" . ('a' x $size) . "',";
  2779.   }
  2780.   if ($length < $limit)
  2781.   {
  2782.     $size=$limit-$length;
  2783.     $res.= "q$i char($size) $self->{'null'},";
  2784.     $values.="'" . ('a' x $size) . "',";
  2785.   }
  2786.   chop($res);
  2787.   chop($values);
  2788.   return ["create table " . $self->{'table_name'} . " ($res)",
  2789.       "insert into " . $self->{'table_name'} . " values ($values)"];
  2790. }
  2791.  
  2792. sub max_limit
  2793. {
  2794.   my ($self)=@_;
  2795.   return $self->{'max_limit'};
  2796. }
  2797.  
  2798. sub cleanup
  2799. {
  2800.   my ($self)=@_;
  2801.   main::safe_query($self->{'cleanup'});
  2802. }
  2803.  
  2804.  
  2805. sub check
  2806. {
  2807.   return 1;
  2808. }
  2809.  
  2810. sub check_query
  2811. {
  2812.   return undef;
  2813. }
  2814.  
  2815. #
  2816. # Used to find max supported index length
  2817. #
  2818.  
  2819. package query_index_length;
  2820.  
  2821. sub new
  2822. {
  2823.   my ($type,$create,$drop,$max_limit)=@_;
  2824.   my $self={};
  2825.   $self->{'create'}=$create;
  2826.   $self->{'cleanup'}=$drop;
  2827.   $self->{'max_limit'}=$max_limit;
  2828.   bless $self;
  2829. }
  2830.  
  2831.  
  2832. sub query
  2833. {
  2834.   my ($self,$limit)=@_;
  2835.   my ($res,$size,$length,$i,$parts,$values);
  2836.   $self->{'limit'}=$limit;
  2837.  
  2838.   $res=$parts=$values="";
  2839.   $size=main::min($main::limits{'max_index_part_length'},$main::limits{'max_char_size'});
  2840.   for ($length=$i=0; $length + $size <= $limit ; $length+=$size, $i++)
  2841.   {
  2842.     $res.= "q$i char($size) not null,";
  2843.     $parts.= "q$i,";
  2844.     $values.= "'" . ('a' x $size) . "',";
  2845.   }
  2846.   if ($length < $limit)
  2847.   {
  2848.     $size=$limit-$length;
  2849.     $res.= "q$i char($size) not null,";
  2850.     $parts.="q$i,";
  2851.     $values.= "'" . ('a' x $size) . "',";
  2852.   }
  2853.   chop($parts);
  2854.   chop($res);
  2855.   chop($values);
  2856.   if ($main::limits{'unique_in_create'} eq 'yes')
  2857.   {
  2858.     return [$self->{'create'} . "($res,unique ($parts))",
  2859.         "insert into crash_q values($values)"];
  2860.   }
  2861.   return [$self->{'create'} . "($res)",
  2862.       "create index crash_q_index on crash_q ($parts)",
  2863.       "insert into crash_q values($values)"];
  2864. }
  2865.  
  2866. sub max_limit
  2867. {
  2868.   my ($self)=@_;
  2869.   return $self->{'max_limit'};
  2870. }
  2871.  
  2872. sub cleanup
  2873. {
  2874.   my ($self)=@_;
  2875.   main::safe_query($self->{'cleanup'});
  2876. }
  2877.  
  2878.  
  2879. sub check
  2880. {
  2881.   return 1;
  2882. }
  2883.  
  2884. sub check_query
  2885. {
  2886.   return undef;
  2887. }
  2888.